A clear explanation of reversing a singly linked list using iterative and recursive approaches.
Problem Restatement
We are given the head of a singly linked list.
We need to reverse the list and return the new head.
Example:
1 -> 2 -> 3 -> 4 -> 5becomes:
5 -> 4 -> 3 -> 2 -> 1The official statement says: given the head of a singly linked list, reverse the list, and return the reversed list.
Input and Output
| Item | Meaning |
|---|---|
| Input | Head of a singly linked list |
| Output | Head of the reversed linked list |
| Operation | Reverse every pointer direction |
| Important detail | The original head becomes the new tail |
Typical node definition:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = nextExample function shape:
def reverseList(head: ListNode) -> ListNode:
...Examples
Example 1:
head = [1,2,3,4,5]Result:
[5,4,3,2,1]Example 2:
head = [1,2]Result:
[2,1]Example 3:
head = []Result:
[]Understanding Pointer Reversal
Suppose we have:
1 -> 2 -> 3Each node points forward.
To reverse the list, we want:
1 <- 2 <- 3The key operation is changing:
current.nextInstead of pointing forward, it should point backward.
The Main Difficulty
When we reverse a pointer, we risk losing the rest of the list.
Example:
1 -> 2 -> 3If we immediately do:
2.next = 1without saving 3, we lose access to the remaining nodes.
So before changing pointers, we must save the next node.
Key Insight
At every step we need three pointers:
| Pointer | Meaning |
|---|---|
prev | Previous node |
current | Current node being processed |
next_node | Saved next node |
Process:
prev <- current -> next_nodeWe reverse:
current.next = prevThen move everything one step forward.
Algorithm
- Initialize:
prev = Nonecurrent = head
- While
currentexists:- Save the next node.
- Reverse the pointer.
- Move
prevforward. - Move
currentforward.
- Return
prev.
At the end, prev becomes the new head.
Walkthrough
Initial list:
1 -> 2 -> 3 -> NoneStart:
prev = None
current = 1First iteration
Save next node:
next_node = 2Reverse pointer:
1 -> NoneMove pointers:
prev = 1
current = 2Second iteration
Current structure:
1 <- 2 -> 3Save:
next_node = 3Reverse:
1 <- 2Move forward:
prev = 2
current = 3Final iteration
Reverse:
1 <- 2 <- 3Now:
current = NoneLoop ends.
Return:
prevwhich points to node 3.
Correctness
The algorithm maintains the invariant that:
prevpoints to the already reversed portion of the list.currentpoints to the remaining unreversed portion.
Initially:
prev = None
current = headSo the reversed portion is empty.
At each iteration:
- The algorithm saves the next node before modifying pointers.
- It reverses the direction of
current.next. - It extends the reversed portion by one node.
- It advances to the next unreversed node.
No nodes are lost because the original next node is stored in next_node.
When the loop finishes, every pointer has been reversed, and prev points to the new head of the fully reversed list.
Therefore the algorithm correctly reverses the linked list.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Each node is visited once |
| Space | O(1) | Only a few pointers are used |
Iterative Implementation
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
prev = None
current = head
while current:
next_node = current.next
current.next = prev
prev = current
current = next_node
return prevCode Explanation
Start with:
prev = None
current = headprev represents the reversed part.
current represents the node being processed.
Save the next node before changing pointers:
next_node = current.nextReverse the pointer:
current.next = prevMove the pointers forward:
prev = current
current = next_nodeAt the end:
return prevbecause prev points to the new head.
Recursive Solution
We can also reverse the list recursively.
Idea:
- Reverse the rest of the list.
- Attach the current node at the end.
Example:
1 -> 2 -> 3Recursive calls reverse:
2 -> 3into:
3 -> 2Then connect:
3 -> 2 -> 1Implementation:
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
new_head = self.reverseList(head.next)
head.next.next = head
head.next = None
return new_headRecursive Code Explanation
Base case:
if not head or not head.next:
return headA list with zero or one node is already reversed.
Reverse the remaining list:
new_head = self.reverseList(head.next)Suppose:
head = 1
head.next = 2After recursion:
2 -> 1?Now reverse the connection:
head.next.next = headBreak the old forward link:
head.next = NoneReturn the final head:
return new_headTesting
def build_list(values):
dummy = ListNode(0)
current = dummy
for value in values:
current.next = ListNode(value)
current = current.next
return dummy.next
def to_list(head):
result = []
while head:
result.append(head.val)
head = head.next
return result
def run_tests():
s = Solution()
head = build_list([1,2,3,4,5])
assert to_list(s.reverseList(head)) == [5,4,3,2,1]
head = build_list([1,2])
assert to_list(s.reverseList(head)) == [2,1]
head = build_list([1])
assert to_list(s.reverseList(head)) == [1]
head = build_list([])
assert to_list(s.reverseList(head)) == []
print("all tests passed")
run_tests()| Test | Why |
|---|---|
[1,2,3,4,5] | Standard reversal |
[1,2] | Small list |
[1] | Single node |
[] | Empty list |