Example 1
ready- Input
head = [ 1, 2, 3, 4, 5 ]- Expected
[ 5, 4, 3, 2, 1 ]- Why
- the tail becomes the head and every link changes direction
A chain can face the other way without changing a single value. You only need to turn each link around.
A singly linked list is a chain of nodes where each node stores a value and a link to the next node. Given the first node, reverse the whole chain and return its new first node.
A few ground rules:
0 <= list length <= 10_000-1_000_000_000 <= Node.val <= 1_000_000_000Hints
If you redirect current.next immediately, you lose the rest of the list. Save that
next node somewhere before changing the link.
Keep previous as the head of the part you've already reversed. Point current.next
at previous, then move both names one node forward.
When current finally becomes null, previous is sitting on the old tail — exactly
the new head you need.
Can you write a recursive version too, then explain why its call stack uses O(n) space even though the pointer work looks the same?
Visible cases
head = [
1,
2,
3,
4,
5
][
5,
4,
3,
2,
1
]head = [
1,
2
][
2,
1
]head = [][]Interview signal
The most direct route turns the list into familiar territory. Walk once to collect its values, then build a fresh list by placing each collected value in front of the one you built last.
def reverse_list(head: ListNode | None) -> ListNode | None:
values: list[int] = []
current = head
while current is not None:
values.append(current.val)
current = current.next
new_head = None
for value in values:
new_head = ListNode(value, new_head)
return new_headFor 4 → 8 → 15, the rebuild grows as 4, then 8 → 4, then 15 → 8 → 4.
It works, but it stores every value and allocates another node for every input node.
Time O(n) — one pass to collect and one to rebuild. Space O(n) for the values and the fresh list.
You don't need new nodes. At every step, keep three positions in view:
current is the node whose link you're about to reverse.next_node protects the untouched remainder.previous is the head of the part already reversed.The loop invariant is a fact that remains true after every iteration: previous
always heads a correctly reversed prefix, while current heads the untouched suffix.
def reverse_list(head: ListNode | None) -> ListNode | None:
previous = None
current = head
while current is not None:
next_node = current.next
current.next = previous
previous = current
current = next_node
return previousSaving next_node before changing current.next is the critical order. Skip that save,
and the first reversal cuts off every node you haven't visited yet.
Time O(n) — each node is visited once. Space O(1) — only three node references move, no matter how long the list is.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
[ 5, 4, 3, 2, 1 ]