LeetCode #206 Easy

Reverse Linked List

Reverse a singly linked list and return the new head.

linked-listrecursion
Open on LeetCode ↗
02

Intuition

Flip one arrow at a time. You need three references each step so the rest of the list is never lost: the already-reversed part (prev), the node being flipped (curr), and the saved next node (nxt).

How to spot this pattern

Reach for the three-pointer flip whenever a problem asks you to change the direction of links rather than the values inside them — reverse a list, reverse a sub-list, reverse in groups of k, or check a palindrome list. The giveaway is a follow-up asking for O(1) extra space: that rules out copying into an array and forces in-place pointer rewiring.

03

Approach

1

Copying values out is wasteful

You could read all values into an array, reverse it, and rebuild the list — but that's O(n) extra space for something that's really just pointer rewiring. The list already holds all the nodes; we only need to flip the direction of each next link, in place.

2

Reverse one link at a time, but save the tail first

The core move is curr.next = prev — point the current node backward at the portion we've already reversed. The catch: the instant you overwrite curr.next, you lose your only handle on the rest of the list. So before rewiring, save nxt = curr.next. With three references — prev (reversed part), curr (node being flipped), nxt (unprocessed remainder) — no node is ever orphaned.

3

Slide the trio forward until the end

Each iteration: save nxt, flip curr.next to prev, then advance prev = curr and curr = nxt. Repeat until curr is null. At that point prev sits on what used to be the tail — the new head — so return it. Empty and single-node lists fall out naturally. One pass, O(n) time, O(1) space.

04

Solution & live demo

1class Solution:
2 def reverseList(self, head):
3 prev = None
4 curr = head
5 while curr:
6 nxt = curr.next
7 curr.next = prev
8 prev = curr
9 curr = nxt
10 return prev
05

Common pitfalls

Returning curr instead of prev

✗ Wrong
while curr:
    ...
    curr = nxt
return curr   # always None
✓ Right
while curr:
    ...
    curr = nxt
return prev   # the old tail

The loop only ends when curr becomes None, so returning curr always returns an empty list. prev is one step behind, which is exactly where the new head sits.

Flipping the pointer before saving the next node

✗ Wrong
curr.next = prev
nxt = curr.next   # already overwritten
curr = nxt
✓ Right
nxt = curr.next   # save first
curr.next = prev
curr = nxt

Once curr.next is reassigned, the original link to the rest of the list is gone — reading it back just hands you prev, and you walk backwards into an infinite loop. Save the tail before you cut it.

Initialising prev to head

✗ Wrong
prev = head
curr = head
✓ Right
prev = None
curr = head

The original head becomes the new tail, and a tail must point at None. Starting prev at head makes node 1 point to itself, producing a cycle that hangs any later traversal.

06

Edge cases

Empty list

curr is null from the start; the loop is skipped and prev (null) is returned.

Single node

One iteration flips its next to null and prev becomes that node — the unchanged head.

Losing the tail

Saving nxt before rewiring guarantees the unprocessed remainder is always reachable.

07

Complexity

Time
O(n)
Space
O(1)
One pass, iterative, three pointers.