Top 12 Linked List Interview Problems, Ranked by Pattern

- Dummy head eliminates head-node edge cases on insertion and deletion; return
dummy.nextat the end. - Fast-slow pointers at 2x speed detect cycles; the same setup at a fixed gap finds the kth-from-end predecessor.
- In-place reversal is three pointers and extends directly to segment and k-group problems.
- Hard problems are compositions: Reorder List is find-middle + reverse + merge, all O(n) and O(1) space.
- Add Two Numbers: loop condition must be
l1 or l2 or carry, or you silently drop the final carry digit. - Merge K Sorted Lists: the heap needs an index tiebreaker or Python raises TypeError on equal node values.
- Reverse Nodes in k-Group: confirm k nodes exist before reversing; initialize
prev = group_nextso the tail reconnects automatically.
Linked list problems look disarmingly simple. One node. One pointer. One moment where you realize you have no idea which pointer is pointing at what and the interviewer is watching.
There are only five fundamental linked list patterns. All twelve linked list interview problems remix those five. Learn them and the hard problems become composition exercises, not memory tests.
The Five Patterns You Actually Need
Dummy head. Insert a placeholder node before the real head. It eliminates special cases for operations that might touch the head node. You return dummy.next at the end. Worth it every time, no matter how silly it looks.
Fast-slow pointers. Two pointers at different speeds. Fast at 2x detects cycles. Fast starting k steps ahead finds the kth-from-end node. The same two-line setup solves four different problems.
In-place reversal. Three-pointer rolling swap: prev, curr, next. Reverse a list, reverse a segment, reverse k-groups. One mechanism, many shapes, infinite opportunities to lose track of which pointer moved.
Multi-step composition. Hard problems chain simpler patterns. Find the middle, reverse the second half, merge. Three separate O(n) passes, O(1) space total. Write each step, then connect them.
Augmented structure. Add a hash map or wrap the list in a class. Copy with random pointer, LRU cache. Sometimes the right data structure is two data structures holding hands.
| # | Problem | Difficulty | Pattern |
|---|---|---|---|
| 1 | Reverse Linked List (LC 206) | Easy | In-place reversal |
| 2 | Merge Two Sorted Lists (LC 21) | Easy | Dummy head |
| 3 | Linked List Cycle (LC 141) | Easy | Fast-slow |
| 4 | Middle of Linked List (LC 876) | Easy | Fast-slow |
| 5 | Remove Nth Node From End (LC 19) | Medium | Fast-slow (gap) |
| 6 | Linked List Cycle II (LC 142) | Medium | Fast-slow (math) |
| 7 | Add Two Numbers (LC 2) | Medium | Dummy head + carry |
| 8 | Reverse Linked List II (LC 92) | Medium | In-place reversal |
| 9 | Copy List with Random Pointer (LC 138) | Medium | Hash map |
| 10 | Reorder List (LC 143) | Medium | Composition |
| 11 | Merge K Sorted Lists (LC 23) | Hard | Heap |
| 12 | Reverse Nodes in k-Group (LC 25) | Hard | In-place reversal |
1. Reverse a Linked List (LC 206), Easy
The session warmup. Every interviewer opens with it. If you stumble here, the rest of the interview is uphill. Know it cold before you walk in.
Three pointers, one pass. prev starts null, curr starts at head. Each iteration: store next, flip curr.next = prev, advance both. Do not think too hard. It is three assignments in a loop.
def reverseList(head): prev, curr = None, head while curr: next_node = curr.next curr.next = prev prev = curr curr = next_node return prev
Pitfall: the recursive version is beautiful. It is also O(n) stack space, and interviewers ask for the iterative version specifically to check whether you know the difference. They will absolutely ask. Say it first.
2. Merge Two Sorted Lists (LC 21), Easy
The dummy node is the unsung hero of linked list problems. Allocate a placeholder node before the merged list, then return dummy.next. You never have to ask "is the merged list empty yet?" because dummy means you always have somewhere to write.
def mergeTwoLists(l1, l2): dummy = ListNode(0) curr = dummy while l1 and l2: if l1.val <= l2.val: curr.next = l1 l1 = l1.next else: curr.next = l2 l2 = l2.next curr = curr.next curr.next = l1 or l2 return dummy.next
Pitfall: forgetting curr.next = l1 or l2. One list will have leftover nodes once the other exhausts. Attach the remainder in one line. If you skip this, your merged list just ends in the middle and you return the wrong answer with complete confidence.
3. Linked List Cycle (LC 141), Easy
Floyd's tortoise and hare. Slow moves one step, fast moves two. If there is a cycle, fast laps slow and they meet. If fast reaches null, there is no cycle. The logic is not complicated. The proof is a little annoying, but you do not need the proof to use it.
def hasCycle(head): slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next if slow is fast: return True return False
Pitfall: use is not == for pointer comparison. Two nodes with equal values are not the same node. You are comparing memory addresses, not values. For the full math on why the meeting is guaranteed, see the Floyd's cycle detection algorithm deep dive.

Both pointers start at head. Fast laps slow inside the cycle. That the meeting is guaranteed is a real theorem, not a vibe.
4. Middle of Linked List (LC 876), Easy
Fast-slow again. When fast reaches the end, slow is at the middle. That is the whole trick.
def middleNode(head): slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next return slow
Pitfall: for even-length lists, this returns the second middle. Some problems want the first. Initialize fast = head.next to shift by one position. Read the problem statement before you code. This specific detail will be in the statement.
5. Remove Nth Node From End (LC 19), Medium
Gap technique. Move fast forward n+1 steps first. Then advance both until fast is null. Slow lands one step before the node to delete.
def removeNthFromEnd(head, n): dummy = ListNode(0, head) slow, fast = dummy, dummy for _ in range(n + 1): fast = fast.next while fast: slow = slow.next fast = fast.next slow.next = slow.next.next return dummy.next
The gap is n+1, not n, because you need the node before the target, not the target itself. You need to do slow.next = slow.next.next, and for that you need to be one step early. The dummy head handles the edge case where n equals the list length, which means deleting the actual head. Without it you are writing a special case for something that should not need one.
6. Linked List Cycle II (LC 142), Medium
Find the cycle entrance, not just its existence. This is where fast-slow goes from "pattern" to "party trick." Phase 1: run fast-slow until they meet. Phase 2: reset one pointer to head, advance both at speed 1. They meet at the cycle start.
The math is real: if there are F nodes before the cycle and C nodes in the cycle, the meeting point satisfies F = kC - (distance from cycle start to meeting point). Resetting to head and stepping at the same speed puts both pointers at the entrance simultaneously. You do not have to re-derive this in the interview. Know the two-phase recipe and move on.
def detectCycle(head): slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next if slow is fast: slow = head while slow is not fast: slow = slow.next fast = fast.next return slow return None
Pitfall: the phase-2 reset happens inside the cycle-detected branch, not at the top of the function. If you reset unconditionally, you get an infinite loop on acyclic lists. Which is its own kind of ironic.
7. Add Two Numbers (LC 2), Medium
Digits stored in reverse order, two lists, produce a sum. Scan both simultaneously, sum values, propagate carry. The loop condition is l1 or l2 or carry, not just l1 or l2.
def addTwoNumbers(l1, l2): dummy = ListNode(0) curr = dummy carry = 0 while l1 or l2 or carry: val = carry if l1: val += l1.val l1 = l1.next if l2: val += l2.val l2 = l2.next carry, val = divmod(val, 10) curr.next = ListNode(val) curr = curr.next return dummy.next
Pitfall: if you stop when both lists exhaust but carry is still 1, you silently drop a digit. Adding 5 + 5 gives you [0] instead of [0, 1]. It passes most test cases and fails the last one. The fix is one word: add or carry to the while condition.
8. Reverse Linked List II (LC 92), Medium
Reverse from position left to right in one pass. Walk to the node before left, then run the standard reversal for (right - left) steps. Sounds straightforward. The implementation has a subtlety that trips almost everyone.
def reverseBetween(head, left, right): dummy = ListNode(0, head) pre = dummy for _ in range(left - 1): pre = pre.next curr = pre.next for _ in range(right - left): next_node = curr.next curr.next = next_node.next next_node.next = pre.next pre.next = next_node return dummy.next
This is the "insert at front of segment" pattern. Each iteration takes next_node and moves it directly after pre. No separate prev pointer inside the segment. One forward pass, one clean result.
9. Copy List with Random Pointer (LC 138), Medium
Each node has next and random. Random points anywhere, including null. You need a deep copy. Two-pass with a hash map: first pass creates all new nodes, second pass wires both pointers. Clear, O(n) time, and you will not introduce bugs at 11pm before your interview.
def copyRandomList(head): if not head: return None old_to_new = {} curr = head while curr: old_to_new[curr] = Node(curr.val) curr = curr.next curr = head while curr: if curr.next: old_to_new[curr].next = old_to_new[curr.next] if curr.random: old_to_new[curr].random = old_to_new[curr.random] curr = curr.next return old_to_new[head]
There is an O(1) space interleaving trick where you weave new nodes between old ones. It is clever. It is also harder to implement correctly under pressure. Use the hash map unless the interviewer explicitly asks for O(1) space. If they ask, draw the interleaving on the whiteboard first and trace it before you type anything.
10. Reorder List (LC 143), Medium
Transform 1→2→3→4→5 into 1→5→2→4→3 in-place. You cannot build a new list. You cannot use O(n) space. You have to do it with the nodes you have. Three steps: find the middle, reverse the second half, merge the two halves alternately.
def reorderList(head): slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next prev, curr = None, slow.next slow.next = None # cut the list while curr: next_node = curr.next curr.next = prev prev = curr curr = next_node first, second = head, prev while second: tmp1, tmp2 = first.next, second.next first.next = second second.next = tmp1 first = tmp1 second = tmp2
Pitfall: slow.next = None is mandatory. Without severing the list at the midpoint, the reversal loop walks back into the first half and you get an infinite cycle. Comment it when you write it so the interviewer knows you did it on purpose.
11. Merge K Sorted Lists (LC 23), Hard
K lists, produce one sorted output. Brute force dumps everything into an array and sorts it, which is O(N log N) but honest. Optimal: a min-heap of size K. Pop the smallest node, push its successor.
import heapq def mergeKLists(lists): dummy = ListNode(0) curr = dummy heap = [] for i, node in enumerate(lists): if node: heapq.heappush(heap, (node.val, i, node)) while heap: val, i, node = heapq.heappop(heap) curr.next = node curr = curr.next if node.next: heapq.heappush(heap, (node.next.val, i, node.next)) return dummy.next
Pitfall: Python's heap compares tuple elements left to right. If two nodes share a value, it tries to compare the ListNode objects directly and crashes with TypeError. The index i as a tiebreaker prevents the comparison from ever reaching the node object. This bug will not appear in small tests. It will appear in the interviewer's test case with identical values. Add the tiebreaker before you run anything.
12. Reverse Nodes in k-Group (LC 25), Hard
Reverse every k consecutive nodes. Fewer than k nodes at the tail stay as-is. This is the hardest standard linked list problem you will see, and it shows up at the end of onsites specifically because the interviewer wants to see how you handle complexity when your brain is tired. Count k nodes ahead first. If you cannot find k nodes, stop. Never start reversing before confirming the group exists.
def reverseKGroup(head, k): dummy = ListNode(0, head) group_prev = dummy while True: kth = group_prev for _ in range(k): kth = kth.next if not kth: return dummy.next group_next = kth.next prev, curr = kth.next, group_prev.next while curr != group_next: next_node = curr.next curr.next = prev prev = curr curr = next_node tmp = group_prev.next group_prev.next = kth group_prev = tmp
The initialization prev = kth.next is the non-obvious part. When the reversal finishes, the node that was first in the group (now the tail) has next pointing to group_next, which is the start of the next unprocessed group. The reconnection happens automatically, without you writing it explicitly. The first time you see this, it looks like a bug. It is not.
Drilling Linked List Interview Problems Under Pressure
Pattern knowledge and interview execution are not the same skill. The reversal pointer juggling in LC 25, the carry loop in LC 2, the two-phase reset in LC 142: these require fluency, not just recall. If you cannot narrate the reasoning out loud while your hands type the pointer updates, you will lose the thread mid-problem.
SpaceComplexity runs voice-based mock interviews where you explain your approach as you code. Linked list problems expose exactly the gap between "I understand this" and "I can explain it under pressure." Use it to drill the narration, not just the code.
For more on the two-pointer family that powers problems 3 through 6, see Two Pointer Technique and fast-slow pointer pattern recognition.
Eight Rules to Know Cold
- Dummy head eliminates almost every head-node edge case. Default to it.
- Fast-slow at 2x detects cycles. Fast n+1 ahead gives you the predecessor for deletion. Same setup, different gap.
- In-place reversal is three pointers. Extend it to segments and k-groups by controlling where the reversal starts and stops.
- Hard problems are compositions. Reorder List is "find middle" plus "reverse" plus "merge."
- Add Two Numbers: loop while
l1 or l2 or carry. Miss the carry and you drop a digit. Silently. - Copy with Random Pointer: two-pass hash map is correct and clear. Use it.
- Merge K Lists: heap with index tiebreaker avoids Python
TypeErroron equal values. Add it before you run. - Reverse in k-Group: confirm the group exists before reversing it. Initialize
prev = group_next.
Further Reading
- Linked List problems on LeetCode, canonical problem set for the full tag
- Floyd's cycle detection (Wikipedia), proof of the two-phase meeting-point argument
- Introduction to Algorithms, CLRS Chapter 10, formal linked list operations including merge and sorting
- Merge K Sorted Lists, GeeksforGeeks, heap vs divide-and-conquer approaches compared
- Linked List data structure (Wikipedia), complete reference for node structure, variants, and complexity table