Reverse Linked List
An easy problem from Linked List. Try it first, open a hint when you are stuck, and read the solution when you are done.
- Easy
- Linked List
The problem
You are given head, the first node of a singly linked list. Each node holds a value, val, and a link, next, to the node after it, and the last node's next is null. Return the first node of the same list in reverse order. An empty list is given as null, and its reverse is null too. The checker follows next from the node you return and compares the values, so you may reuse the given nodes or build new ones.
What to write
type ListNode = { val: number; next: ListNode | null };
function solve(head: ListNode | null): ListNode | nullExample 1
Input head = {"val":1,"next":{"val":2,"next":null}} Output {"val":2,"next":{"val":1,"next":null}}
The list is 1 → 2: the node holding 1 comes first and links to the node holding 2. In reverse order 2 comes first and links to 1, and 1 is now the last node, so its link is null.
Example 2
Input head = null Output null
The input is null, which stands for a list with no nodes. There is nothing to put in a different order, so the reversed list is empty as well and the answer is null.
Constraints
0–500 acyclic nodes; integer val; next is a node or null.
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1: Use the constraints
A node only knows the node after it, so you can walk the list forward but never backward. The list may be empty, given as null, or hold a single node. Both of those are already their own reverse.
Hint 2: Ask a smaller question
Draw 1 → 2 → 3 on paper and look only at the node 2. Where must its link point in the reversed list? If you change that link right away, how will you still reach the node 3?
Hint 3: Name the pattern
No node has to move and no value has to change. Each node only needs its link turned around, so that it points at the node before it. Changing the links of existing nodes is linked list pointer rewiring. The signal: the answer is the same nodes in a new order. Read the lesson on linked list pointer rewiring.
Hint 4: State the invariant
The list is always in two parts. The reversed part holds the nodes you have visited, with their links already turned. The rest is still in its original order. You hold the first node of each part, so no node is ever out of reach.
Hint 5: Sketch the pseudocode
reversed = null. While
headis not null: save the node afterhead; point thenextofheadat reversed; reversed =head;head= the saved node. Return reversed.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
Approach
Save the next pointer before changing it. Point the current node backward, then advance the previous and current pointers.
The slow way
Walk the list and collect every value in an array. Then walk the list again and write the values back in reverse order. The answer is right, but the array keeps a copy of all n values, when the nodes already hold everything the answer needs.
The insight
Reversing a list does not move any node. Only the links change direction: a node that pointed at the node after it must point at the node before it. If you remember the node before as you walk, you can turn each link the moment you pass it.
Step by step
- Start with an empty reversed part. The reversed part is the piece of the list whose links are already turned. It starts empty, written as null. Null is also the link the first node needs, because that node ends up last.
- Save the next node before this node's link is changed. The link is your only way to reach the rest of the list. Once the link points somewhere else, the next node can be found only if you saved that node first.
- Turn this node's link around to point at the reversed part. In the reversed list a node is followed by the node that used to come before it, and that node is the first one of the reversed part.
- This node now leads the reversed part; step to the saved node. The node has joined the front of the reversed part, so the reversed part now starts with this node. The saved node is the first one whose link is still unturned.
- Every node is turned, so the reversed part is the answer. The loop ends when no node is left to visit. The reversed part then starts with the old last node and holds every node. For an empty list the reversed part is still null, which is the right answer.
The same numbered steps are the comments in each solution.
JavaScript
function solve(head) {
// 1. Start with an empty reversed part
let prev = null;
while (head) {
// 2. Save the next node before this node's link is changed
const next = head.next;
// 3. Turn this node's link around to point at the reversed part
head.next = prev;
// 4. This node now leads the reversed part; step to the saved node
prev = head;
head = next;
}
// 5. Every node is turned, so the reversed part is the answer
return prev;
}TypeScript
type ListNode = { val: number; next: ListNode | null };
function solve(head: ListNode | null): ListNode | null {
// 1. Start with an empty reversed part
let prev = null;
while (head) {
// 2. Save the next node before this node's link is changed
const next = head.next;
// 3. Turn this node's link around to point at the reversed part
head.next = prev;
// 4. This node now leads the reversed part; step to the saved node
prev = head;
head = next;
}
// 5. Every node is turned, so the reversed part is the answer
return prev;
}
Python
def solve(head):
# 1. Start with an empty reversed part
prev = None
while head:
# 2. Save the next node before this node's link is changed
after = head.next
# 3. Turn this node's link around to point at the reversed part
head.next = prev
# 4. This node now leads the reversed part; step to the saved node
prev = head
head = after
# 5. Every node is turned, so the reversed part is the answer
return prev
Example 1, traced
Input head = {"val":1,"next":{"val":2,"next":null}} Output {"val":2,"next":{"val":1,"next":null}}
| Node | Next node, saved | Its link now points at | Reversed part | Rest of the list |
|---|---|---|---|---|
| Before the first | - | - | empty | 1 → 2 |
| 1 | 2 | null | 1 | 2 |
| 2 | null | 1 | 2 → 1 | empty |
| None left | - | - | Return 2 → 1 | empty |
Why it works
Before every round, the reversed part holds the visited nodes in reverse order, and the rest holds the other nodes in their original order. One round moves the first node of the rest to the front of the reversed part. When the rest is empty, the reversed part is the whole list, reversed.
Time and space
Time O(n), extra space O(1). The loop visits each node once and does a fixed amount of work for it, so the time is O(n) for n nodes. It creates no nodes and keeps three references however long the list is, so the extra space is O(1).
n and m are input sizes, h is a tree's height, V and E are a graph's vertices and edges. The bounds describe this reference solution.
Watch out
- Save the next node before you change the link. If you change the link first and then follow it, you land in the reversed part: the loop ends after one node and the answer is that single node.
- Return the front of the reversed part, not the node you were given. That node is now the last one and its link is null, so returning it gives a list of one node.
- Loop until the current node is null, not until its link is null. Stopping one node early leaves the last node out of the answer, and a single node comes back as an empty list.