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.

linked list
interview prep
python
two pointers
recursion

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:

  1. Save the next node
  2. Reverse the current pointer
  3. 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.

python
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

Iterative reversal

This is the most common interview solution.

python
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 prev

How it works

Suppose the list is 1 -> 2 -> 3 -> None.

At the start:

  • prev = None
  • curr = 1

Iteration 1:

  • Save 2
  • Point 1.next to None
  • Move prev to 1
  • Move curr to 2

Iteration 2:

  • Save 3
  • Point 2.next to 1
  • Move prev to 2
  • Move curr to 3

Iteration 3:

  • Save None
  • Point 3.next to 2
  • Move prev to 3
  • Move curr to None

Now prev is the new head: 3 -> 2 -> 1 -> None.

Worked example

If you start with:

Code
1 -> 2 -> 3 -> 4 -> None

The list becomes:

Code
4 -> 3 -> 2 -> 1 -> None

A 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.

python
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 False

Why 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:

Code
1 -> 2 -> 3 -> 4 -> 5
         ^         |
         |_________|

Pointer movement might look like this:

Stepslowfast
011
123
235
344

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.

python
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 ptr1

3) 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.

python
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.next

Why 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:

Code
l1: 1 -> 3 -> 5
l2: 2 -> 4 -> 6

Compare heads step by step:

  • 1 vs 2 → take 1
  • 3 vs 2 → take 2
  • 3 vs 4 → take 3
  • 5 vs 4 → take 4
  • 5 vs 6 → take 5
  • l1 is exhausted → append 6

Result:

Code
1 -> 2 -> 3 -> 4 -> 5 -> 6

Complexity analysis

Most linked list operations here are linear because you visit each node a constant number of times.

ProblemApproachTime ComplexitySpace ComplexityNotes
Reverse linked listIterativeO(n)O(1)Best interview default
Reverse linked listRecursiveO(n)O(n)Simpler conceptually, uses call stack
Detect cycleSlow/fast pointersO(n)O(1)Standard solution
Find cycle entrySlow/fast + reset pointerO(n)O(1)Follows from cycle detection
Merge two sorted listsIterative with dummy nodeO(m+n)O(1)Most practical solution
Merge two sorted listsRecursiveO(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:

python
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_head

This 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 next before rewiring curr.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_node first.
  • Forgetting fast.next in cycle detection: check both fast and fast.next before moving two steps.
  • Not advancing the tail in merge logic: after attaching a node, move tail forward.
  • 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

  1. Reverse Linked List
  2. Linked List Cycle
  3. Merge Two Sorted Lists
  4. Remove Nth Node From End of List
  5. Reorder List

Practice this pattern interactively

Generate a step-by-step lesson for any LeetCode problem and watch the algorithm run, variable by variable.

Start a free lesson

Related posts