Reverse Linked List – Solution & Complexity

1. Understand the Goal

  • The input is a chain of nodes: 1 -> 2 -> 3 -> null.
  • Reversing it means every next pointer should point the other way: 3 -> 2 -> 1 -> null.
  • The new head is the old tail, so the function must return the node that used to be last.

2. Track Three Pointers

  • Walking the list forward while rewriting next pointers destroys the way back unless you keep a reference to what came before.
  • Keep three pointers as you walk: prev (already-reversed portion), curr (node being processed), and next_node (saved before you overwrite curr.next).
  • Start with prev = None since the new tail's next must be null.
def reverse_list(head):
    prev = None
    curr = head
    return prev

3. Rewire One Node at a Time

  • Save curr.next before overwriting it, so you don't lose the rest of the list.
  • Point curr.next backward at prev.
  • Advance both prev and curr one step forward for the next iteration.
def reverse_list(head):
    prev = None
    curr = head
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node
    return prev

4. Confirm the Loop Termination and Complexity

  • The loop stops when curr becomes None, meaning every original node has been rewired.
  • At that point prev holds the new head (the old tail), which is exactly what the function returns.
  • Each node is visited once, so time complexity is O(n); only three pointers are kept, so space complexity is O(1).
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


def reverse_list(head: ListNode) -> ListNode:
    prev = None
    curr = head
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node
    return prev

5. Alternative: Recursive Reversal

  • Recursively reverse everything after the head first, then fix up the one link at the current level.
  • Base case: an empty list or single node is already reversed.
  • After the recursive call, head.next is the new tail, so set head.next.next = head and detach head.next to avoid a two-node cycle.
  • This trades the O(1) space of the iterative version for O(n) call-stack space.
def reverse_list(head: ListNode) -> ListNode:
    if head is None or head.next is None:
        return head
    new_head = reverse_list(head.next)
    head.next.next = head
    head.next = None
    return new_head

FAQ