Reorder List
Problem
head of a singly linked list
L0 → L1 → … → Ln, rearrange its nodes in place into
L0 → Ln → L1 → Ln-1 → L2 → … (first, last,
second, second-last, …). Only links may change, not node values. Nothing is
returned.[1,2,3,4]Output[1,4,2,3][1,2,3,4,5]Output[1,5,2,4,3]1 ≤ n ≤ 5 × 104 · 1 ≤ Node.val ≤ 1000
Try it yourself
class Solution {
public void reorderList(ListNode head) {
}
}
Instinct Nodes joined by next pointers and the task is to reverse, splice, merge, reorder or remove in place - grab a dummy head and rewire pointers carefully.
Memory hack Save next, flip, step - never let go of a rope before you've grabbed the next one.
Open the Linked List Techniques guide →Approaches
Brute ForceRepeatedly Detach the Tail
O(n²)Space O(1)Standing at cur, walk to the node before the tail, unhook the tail
and splice it right after cur; then jump cur two steps
(past the spliced node). Stop once fewer than three nodes remain from
cur. Finding the tail every time is what makes it quadratic.
public void reorderList(ListNode head) { ListNode cur = head; while (cur != null && cur.next != null && cur.next.next != null) { ListNode beforeTail = cur; while (beforeTail.next.next != null) beforeTail = beforeTail.next; ListNode tail = beforeTail.next; beforeTail.next = null; // detach the tail tail.next = cur.next; // splice it right after cur cur.next = tail; cur = tail.next; } }
No extra memory, but each step re-walks the list — too slow for 5×104.
BetterArray of Nodes + Two Pointers
O(n)Space O(n)Store every node in an ArrayList so the tail side is reachable by
index. Pointers i (front) and j (back) take turns:
link i → j, advance i, link j → i,
retreat j. The node where they meet becomes the new tail.
public void reorderList(ListNode head) { if (head == null) return; List<ListNode> nodes = new ArrayList<>(); for (ListNode c = head; c != null; c = c.next) nodes.add(c); int i = 0, j = nodes.size() - 1; while (i < j) { nodes.get(i).next = nodes.get(j); i++; if (i == j) break; nodes.get(j).next = nodes.get(i); j--; } nodes.get(i).next = null; // meeting point is the new tail }
Linear and easy to get right, but stores n references.
OptimalFind Middle, Reverse Second Half, Merge
O(n)Space O(1)Three classic building blocks: fast/slow stops slow at the end of
the first half; reversing slow.next gives Ln, Ln-1, …;
cutting slow.next = null separates the halves. Then weave: each node of
the reversed half is inserted after the matching node of the first half.
public void reorderList(ListNode head) { if (head == null || head.next == null) return; ListNode slow = head, fast = head; while (fast.next != null && fast.next.next != null) { slow = slow.next; fast = fast.next.next; } ListNode second = reverse(slow.next); slow.next = null; // split into two lists ListNode first = head; while (second != null) { ListNode n1 = first.next, n2 = second.next; first.next = second; second.next = n1; first = n1; second = n2; } } private ListNode reverse(ListNode node) { ListNode prev = null; while (node != null) { ListNode next = node.next; node.next = prev; prev = node; node = next; } return prev; }
Linear time, constant memory — the expected interview answer.
At a glance
| Level | Approach | Time | Space |
|---|---|---|---|
| Brute Force | Repeatedly Detach the Tail | O(n²) | O(1) |
| Better | Array of Nodes + Two Pointers | O(n) | O(n) |
| Optimal | Find Middle, Reverse Second Half, Merge | O(n) | O(1) |
- Not cutting
slow.next = null— the halves stay connected and form a cycle. - Swapping values instead of relinking nodes — violates the statement.
- Losing
first.next/second.nextbefore rewiring during the merge.
- Point out the first half is never shorter, so loop on the reversed half.
- Mention that this one problem combines three patterns: middle, reverse, merge.
- Verify with both even
[1,2,3,4]and odd[1,2,3,4,5]lengths.