Reorder the linked list
A classic linked list problem — one exercise that brushes several core ideas at once:
- finding the middle (slow / fast pointers)
- reversing a chain in place
-
merging two lists by rewiring
nextpointers
Problem
Given the head of a singly linked list, the list can be written as:
L0 → L1 → … → Ln-1 → Ln
Reorder it to:
L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …
Example with numbers:
1 → 2 → 3 → 4 → 5 becomes 1 → 5 → 2 → 4 → 3
1 → 2 → 3 → 4 becomes 1 → 4 → 2 → 3
Mental model: three steps
step 1: find the middle of the list
step 2: reverse the second half
step 3: merge the two halves
L0 → L1 → … → slow | slow.next → … → Ln
|
+-- firstll secondll (then reversed)
|
v
zip: L0 → Ln → L1 → Ln-1 → …
After step 1 you have firstll (head) and secondll (slow.next). Set slow.next = null so the list is cut in two. Step 2 makes secondll start at the old tail. Step 3 alternates links between firstll and secondll.
Step 1 — Find the middle (dry run)
Code shape:
let slow = head;
let fast = head;
while (fast && fast.next) {
fast = fast.next.next;
if (!fast) {
break;
}
slow = slow.next;
}
let firstll = head;
let secondll = slow.next;
slow.next = null;
Move fast two steps first. Only if fast is still non-null do you move slow one step. If fast becomes null, stop without moving slow again.
Odd: 1 → 2 → 3 → 4 → 5
| Loop | fast after fast = fast.next.next
|
slow after | stop? |
|---|---|---|---|
| start | 1 | 1 | |
| 1 | 3 | 2 | |
| 2 | 5 | 3 | |
| 3 | null | 3 |
break (slow unchanged) |
-
firstll:1 → 2 → 3(slow.next = null) -
secondll:4 → 5
Even: 1 → 2 → 3 → 4
| Loop | fast after jump | slow after | stop? |
|---|---|---|---|
| start | 1 | 1 | |
| 1 | 3 | 2 | |
| 2 | null | 2 | break |
-
firstll:1 → 2 -
secondll:3 → 4
Step 2 — Reverse secondll (dry run)
Same loop as in your code: curr, prev, future.
let curr = secondll;
let prev = null;
let future;
while (curr) {
future = curr.next;
curr.next = prev;
prev = curr;
curr = future;
}
secondll = prev;
Starting from 4 → 5 (odd example)
| curr | future | after curr.next = prev
|
prev | curr next |
|---|---|---|---|---|
| 4 | 5 | null ← 4 | 4 | 5 |
| 5 | null | null ← 4 ← 5 | 5 | null |
secondll = prev → 5 → 4
Starting from 3 → 4 (even example) → 4 → 3
Step 3 — Merge (dry run)
let firstllnext;
let secondllnext;
while (firstll && secondll) {
firstllnext = firstll.next;
secondllnext = secondll.next;
firstll.next = secondll;
secondll.next = firstllnext;
firstll = firstllnext;
secondll = secondllnext;
}
Each iteration: save both .next, plug second right after first, put the saved first .next after second, then walk both pointers forward.
Odd example — after step 1 and 2
firstll: 1 → 2 → 3
secondll: 5 → 4
| Round | firstll | secondll | wires | list from head |
|---|---|---|---|---|
| start | 1 | 5 | two separate chains | |
| 1 | 2 | 4 | 1→5, 5→2 |
1 → 5 → 2 → 3 and 4
|
| 2 | 3 | null | 2→4, 4→3 | 1 → 5 → 2 → 4 → 3 |
| done | 3 | — | loop ends | 1 → 5 → 2 → 4 → 3 |
When secondll is null, 3 is already the tail. No extra work.
Even example
firstll: 1 → 2
secondll: 4 → 3
| Round | firstll | secondll | list from head |
|---|---|---|---|
| 1 | 2 | 3 |
1 → 4 → 2 and 3
|
| 2 | null | null | 1 → 4 → 2 → 3 |
Full solution (JavaScript)
var reorderList = function (head) {
let slow = head;
let fast = head;
while (fast && fast.next) {
fast = fast.next.next;
if (!fast) {
break;
}
slow = slow.next;
}
let firstll = head;
let secondll = slow.next;
slow.next = null;
let curr = secondll;
let prev = null;
let future;
while (curr) {
future = curr.next;
curr.next = prev;
prev = curr;
curr = future;
}
secondll = prev;
let firstllnext;
let secondllnext;
while (firstll && secondll) {
firstllnext = firstll.next;
secondllnext = secondll.next;
firstll.next = secondll;
secondll.next = firstllnext;
firstll = firstllnext;
secondll = secondllnext;
}
return firstll;
};
The list is reordered in place starting from head. The return value is not what you use; the rewired nodes from head are the answer.
What to remember
| Step | Variables in your code |
|---|---|
| Middle |
slow, fast, then firstll / secondll, cut with slow.next = null
|
| Reverse |
curr, prev, future → secondll = prev
|
| Merge |
firstllnext, secondllnext, alternate .next
|
The pattern is always: split → reverse the back → zip.
Top comments (0)