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).
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.
Approach
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.
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.
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.
Solution & live demo
Common pitfalls
Returning curr instead of prev
while curr:
...
curr = nxt
return curr # always Nonewhile curr:
...
curr = nxt
return prev # the old tailThe 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
curr.next = prev nxt = curr.next # already overwritten curr = nxt
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
prev = head curr = head
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.
Edge cases
curr is null from the start; the loop is skipped and prev (null) is returned.
One iteration flips its next to null and prev becomes that node — the unchanged head.
Saving nxt before rewiring guarantees the unprocessed remainder is always reachable.