Linked List Tricks and Patterns: Reverse, Detect Cycles, and Merge Sorted Lists
Master core linked list interview patterns with step-by-step intuition, Python code, and worked examples for reversing, cycle detection, and merging sorted lists.
Why linked list problems matter in interviews
Linked lists show up in interviews because they test whether you can reason about pointers, not just arrays. The code is usually short, but the thinking is not. If you can handle linked list questions well, you usually understand traversal, state management, edge cases, and how to avoid breaking references.
The good news is that most linked list interview problems are built from a small set of patterns. Once you learn those patterns, you can solve a lot of seemingly different questions with the same mental toolkit.
This post focuses on three core moves:
- Reverse a linked list
- Detect a cycle
- Merge sorted lists
These are foundational because they recur in many forms: reordering nodes, finding middle points, removing elements, palindrome checks, intersection detection, and more.
Problem statement
A linked list is a sequence of nodes, where each node stores a value and a reference to the next node. Unlike arrays, nodes are not stored contiguously, so you cannot index into them directly.
That changes how you solve problems:
- You traverse with pointers instead of indices.
- You must preserve references carefully when rewiring nodes.
- Edge cases matter: empty list, one node, two nodes, and lists with cycles.
Interviewers often ask you to implement operations such as:
- Reverse a linked list in-place
- Determine whether a cycle exists
- Merge two sorted linked lists
The pattern behind these tasks is less about memorizing code and more about recognizing pointer movement and local rewiring.
Intuition and core insights
1. Reversal is about changing direction one step at a time
When you reverse a linked list, each node’s next pointer must point backward instead of forward. The key is that if you change a pointer too early, you can lose the rest of the list.
The safe pattern is:
- Save the next node
- Reverse the current pointer
- Move forward
You only need three pointers: prev, curr, and next_node.
2. Cycle detection is about comparing two speeds
If a linked list has a cycle, a fast pointer and a slow pointer will eventually meet inside the loop. If there is no cycle, the fast pointer reaches the end first.
This is a classic two-pointer technique, often called Floyd’s Tortoise and Hare algorithm.
3. Merging sorted lists is about repeatedly choosing the smaller head
When two linked lists are already sorted, the smallest remaining element is always at one of the two heads. You do not need to search the entire list. You just compare the current nodes and attach the smaller one to the merged result.
This is why linked list merge problems are a natural fit for iterative pointer manipulation or recursion.
Step-by-step approach with Python code
1) Reverse a linked list
Let’s define a basic node first.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = nextIterative reversal
This is the most common interview solution.
def reverse_list(head: ListNode) -> ListNode:
prev = None
curr = head
while curr:
next_node = curr.next # save the rest of the list
curr.next = prev # reverse the pointer
prev = curr # move prev forward
curr = next_node # move curr forward
return prevHow it works
Suppose the list is 1 -> 2 -> 3 -> None.
At the start:
prev = Nonecurr = 1
Iteration 1:
- Save
2 - Point
1.nexttoNone - Move
prevto1 - Move
currto2
Iteration 2:
- Save
3 - Point
2.nextto1 - Move
prevto2 - Move
currto3
Iteration 3:
- Save
None - Point
3.nextto2 - Move
prevto3 - Move
currtoNone
Now prev is the new head: 3 -> 2 -> 1 -> None.
Worked example
If you start with:
1 -> 2 -> 3 -> 4 -> NoneThe list becomes:
4 -> 3 -> 2 -> 1 -> NoneA useful way to think about this: each node gets “pulled” from the front of the remaining list and inserted at the front of the reversed list.
2) Detect a cycle in a linked list
Cycle detection is one of the most important linked list patterns.
def has_cycle(head: ListNode) -> bool:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return FalseWhy this works
If the list has no cycle, fast eventually hits None.
If the list has a cycle, fast moves two steps at a time while slow moves one. Once both pointers enter the loop, the faster pointer gains one node per iteration and eventually catches the slower one.
Worked example
Consider this cyclic list:
1 -> 2 -> 3 -> 4 -> 5
^ |
|_________|Pointer movement might look like this:
| Step | slow | fast |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 2 | 3 |
| 2 | 3 | 5 |
| 3 | 4 | 4 |
At step 3, both pointers meet, so there is a cycle.
Common follow-up: find the cycle entry
Sometimes the interviewer asks where the cycle begins. After slow and fast meet, reset one pointer to head and move both one step at a time. Their meeting point is the cycle entry.
def detect_cycle_start(head: ListNode) -> ListNode:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
break
else:
return None
ptr1 = head
ptr2 = slow
while ptr1 != ptr2:
ptr1 = ptr1.next
ptr2 = ptr2.next
return ptr13) Merge two sorted linked lists
This is another classic linked list pattern. You compare the current heads of two sorted lists and stitch the smaller one into the result.
def merge_two_lists(l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode()
tail = dummy
while l1 and l2:
if l1.val <= l2.val:
tail.next = l1
l1 = l1.next
else:
tail.next = l2
l2 = l2.next
tail = tail.next
tail.next = l1 if l1 else l2
return dummy.nextWhy a dummy node helps
A dummy node removes special handling for the head of the merged list. You always attach new nodes after tail, and dummy.next becomes the real head at the end.
Worked example
Merge these lists:
l1: 1 -> 3 -> 5
l2: 2 -> 4 -> 6Compare heads step by step:
1vs2→ take13vs2→ take23vs4→ take35vs4→ take45vs6→ take5l1is exhausted → append6
Result:
1 -> 2 -> 3 -> 4 -> 5 -> 6Complexity analysis
Most linked list operations here are linear because you visit each node a constant number of times.
| Problem | Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|---|
| Reverse linked list | Iterative | O(n) | O(1) | Best interview default |
| Reverse linked list | Recursive | O(n) | O(n) | Simpler conceptually, uses call stack |
| Detect cycle | Slow/fast pointers | O(n) | O(1) | Standard solution |
| Find cycle entry | Slow/fast + reset pointer | O(n) | O(1) | Follows from cycle detection |
| Merge two sorted lists | Iterative with dummy node | O(m+n) | O(1) | Most practical solution |
| Merge two sorted lists | Recursive | O(m+n) | O(m+n) | Cleaner, but recursive overhead |
Recursive reversal example
Some interviewers like to see whether you can reason recursively. Here is the recursive version of reverse list:
def reverse_list_recursive(head: ListNode) -> ListNode:
if not head or not head.next:
return head
new_head = reverse_list_recursive(head.next)
head.next.next = head
head.next = None
return new_headThis works, but you should know the tradeoff: it uses the call stack, so the space cost is O(n).
How to recognize the pattern in an interview
When you read a linked list problem, ask yourself:
- Do I need to rewire pointers, or just inspect values?
- Can I solve this with one pass?
- Is there a natural slow/fast pointer setup?
- Would a dummy node simplify head handling?
- Am I accidentally losing the rest of the list when I update a pointer?
A few recurring heuristics help a lot:
- Use a dummy node whenever the head might change.
- Save
nextbefore rewiringcurr.next. - Think in terms of local invariants: what is true before and after each loop iteration?
- Draw the nodes and arrows if you feel unsure.
Common mistakes to avoid
- Losing the rest of the list during reversal: always store
next_nodefirst. - Forgetting
fast.nextin cycle detection: check bothfastandfast.nextbefore moving two steps. - Not advancing the tail in merge logic: after attaching a node, move
tailforward. - Handling head edge cases separately when a dummy node would simplify everything.
- Confusing node equality with value equality: in pointer problems, you often care whether two references point to the same node.
Related problems
Once you understand these three patterns, many other linked list questions become easier:
- Remove nth node from end of list
- Find middle of linked list
- Palindrome linked list
- Reorder list
- Add two numbers
- Intersection of two linked lists
- Copy list with random pointer
- Reverse nodes in k-group
These often combine the same building blocks: two pointers, reversal, dummy nodes, and careful traversal.
Key takeaways
- Linked list interviews test pointer reasoning more than syntax.
- Reversal, cycle detection, and merging sorted lists are the core patterns worth mastering first.
- Save the next pointer before rewiring links.
- Use slow/fast pointers for cycles and middle-related problems.
- Use a dummy node to simplify list construction.
- Most linked list solutions are O(n) time and O(1) extra space if done iteratively.
Soft CTA
If you'd like to see the variables update live as you step through, check out codebrew.ai.
Practice these next
- Reverse Linked List
- Linked List Cycle
- Merge Two Sorted Lists
- Remove Nth Node From End of List
- Reorder List

