Skip to content
← All posts

Reverse Linked List: The Pointer Swap Technique

6 min read
leetcodeproblemeasylinked-list

Reverse Linked List is LeetCode problem 206. It is one of the most classic interview questions, and for good reason. It tests whether you truly understand how pointers work. Not in theory. In practice, under pressure, with a whiteboard marker in your hand.

The problem is rated Easy, but it trips people up constantly. If you cannot reverse a linked list from memory in under two minutes, you will struggle with every linked list problem that builds on top of it.

The problem

You are given the head of a singly linked list. Reverse the list and return the new head.

Example: 1 -> 2 -> 3 -> 4 -> 5 -> null becomes 5 -> 4 -> 3 -> 2 -> 1 -> null.

before12345nullafter54321null
Every arrow flips direction. The old tail becomes the new head.

Why this is tricky

With arrays, reversing is simple: swap the first and last elements, then move inward. You have random access to any index.

Linked lists do not give you that luxury. Each node only knows about the next node. There is no "previous" pointer. There is no way to jump to the end. You are stuck walking forward, one node at a time.

So when you point node 2's next to node 1 (reversing that arrow), you lose your reference to node 3. The chain breaks. You are stranded.

The fix: save a reference to the next node before you break the link. That is the entire trick.

The three-pointer technique

You need three pointers:

  • prev - the node behind curr (starts as null)
  • curr - the node you are currently processing (starts at head)
  • next_node - a temporary save of curr.next before you overwrite it

At each step:

  1. Save curr.next into next_node (so you do not lose it)
  2. Point curr.next to prev (reverse the arrow)
  3. Move prev forward to curr
  4. Move curr forward to next_node

When curr becomes null, you have processed every node. prev now points to the last node you visited, which is the new head of the reversed list. Return prev.

Visual walkthrough

Let's trace through reversing 1 -> 2 -> 3 -> 4 -> null. Watch prev (purple) and curr (amber) as they march through the list, flipping each arrow as they go.

Initial state: prev = null, curr = 1

1234curr

prev is null (not shown). curr starts at the head.

Step 1: Save next = 2. Point 1.next = null. Move prev and curr right.

1234prevcurr

Node 1 now points to null. We move prev to 1, curr to 2.

Step 2: Save next = 3. Point 2.next = 1. Move prev and curr right.

1234prevcurr

Node 2 now points back to 1. prev moves to 2, curr moves to 3.

Step 3: Save next = 4. Point 3.next = 2. Move prev and curr right.

1234prevcurr

Node 3 now points back to 2. prev moves to 3, curr moves to 4.

Step 4: Save next = null. Point 4.next = 3. curr becomes null. Done!

1234prev

All arrows reversed. prev points to 4, which is our new head. Return prev.

Notice the pattern: at each step, exactly one arrow gets reversed. By the end, every arrow points backwards and prev is sitting on the new head. Clean and predictable.

The iterative solution

def reverseList(head):
    prev = None
    curr = head

    while curr:
        next_node = curr.next  # save
        curr.next = prev       # reverse
        prev = curr            # advance prev
        curr = next_node       # advance curr

    return prev

Four lines inside the loop, each doing exactly one thing. This is one of those solutions where every line is load-bearing. Remove any one of them and it breaks.

A common bug is forgetting to save curr.next before overwriting it. If you write curr.next = prev first, you have lost your only way forward. Always save before you swap.

The recursive solution

The recursive approach is more elegant but harder to reason about. The idea: assume the rest of the list is already reversed. Then fix the connection between the current node and the next node.

def reverseList(head):
    if not head or not head.next:
        return head

    new_head = reverseList(head.next)
    head.next.next = head
    head.next = None

    return new_head

Here is what is happening:

  1. Base case: If the list is empty or has one node, it is already reversed. Return it.
  2. Recurse: Reverse everything after head. The returned new_head is the tail of the original list, which is now the head of the reversed list.
  3. Fix the link: head.next is the node right after head. That node's next should now point back to head. So head.next.next = head.
  4. Break the old link: Set head.next = None so the original forward arrow is removed.
  5. Pass up the new head: new_head bubbles all the way back up the call stack unchanged.

The recursive version is elegant, but it uses O(n) stack space. For very long lists, that can be a problem. The iterative version is O(1) space and generally preferred in interviews.

Complexity analysis

Time: O(n) for both approaches. You visit each node exactly once. There is no way to do better since you need to touch every arrow.

Space: O(1) for the iterative approach. You only use three pointer variables regardless of list length. The recursive approach is O(n) space due to the call stack.

Edge cases to watch for

  • Empty list (head is null). The while loop never runs. prev stays None. Return None. Correct.
  • Single node. The while loop runs once, sets curr.next = None (it was already null), and moves on. Returns the single node. Correct.
  • Two nodes. The simplest case where an actual reversal happens. Good for verifying your logic by hand.
  • Very long list. The iterative solution handles this fine. The recursive solution might hit a stack overflow in languages without tail-call optimization (which includes Python).

The Building Blocks

This problem is built from one core building block:

In-place pointer reversal. You have a chain of references, and you need to flip them one by one without losing your place. The technique: always save the next reference before you overwrite it, then advance your "previous" and "current" pointers in lockstep.

This brick shows up everywhere in linked list problems:

  • Reverse Linked List II (LeetCode 92) reverses only a subsection of the list. Same pointer swap, but you need to reconnect the boundaries.
  • Palindrome Linked List (LeetCode 234) reverses the second half, then compares it to the first half.
  • Reorder List (LeetCode 143) splits the list in half, reverses the back half, then interleaves the two halves.
  • Reverse Nodes in k-Group (LeetCode 25) applies the reversal in chunks of k nodes. Hard problem, but the inner loop is exactly this technique.
  • Swap Nodes in Pairs (LeetCode 24) is a special case of k-group reversal with k = 2.

Once you can reverse a linked list without thinking, you unlock an entire family of problems. This is not a standalone trick. It is a fundamental building block.

The "save before you swap" principle appears in many contexts beyond linked lists. Whenever you need to rearrange pointers or references in-place, the pattern is the same: save what you are about to overwrite, make the change, then advance using what you saved.

Why you will forget this (and how to fix it)

This is a six-line solution. You will read it, understand it, and feel confident. Then in an interview two weeks from now, you will mix up the order of the pointer assignments and spend five minutes debugging.

The problem is not understanding. It is recall under pressure. You need to have typed this solution from scratch enough times that your fingers know the order: save, reverse, advance prev, advance curr. No hesitation.

Spaced repetition makes this automatic. You type it today, again in two days, again in a week. After a few reps, the pointer dance is muscle memory. You do not think about which variable to update first. You just do it.

Related posts

  • Merge Sorted Array - Another problem where pointer manipulation order matters and getting it wrong means losing data
  • Valid Parentheses - A different data structure (stacks), but the same idea of tracking state as you walk through a sequence