Reorder List (Half Reverse, Merge)
Overview
Reorder list means rearranging the list so that nodes alternate between the first half and the second half in reverse order: L0 β Ln β L1 β Lnβ1 β L2 β β¦ You do not create new nodes; only rewire pointers. The approach: (1) find the middle with Fast and Slow Pointers, (2) reverse the second half with Reverse In-Place, (3) merge the first half and the reversed second half alternately. All in O(n) time and O(1) space.
Key idea: After splitting at the middle and reversing the second half, you have two lists: [L0, L1, β¦] and [Ln, Lnβ1, β¦]. Weave them one node at a time.
When to Use
- Reorder list β Exact problem: L0 β Ln β L1 β Lnβ1 β β¦
- Any "interleave two halves" β Same pattern: find middle, reverse second half (or not, depending on desired order), merge.
How It Works
- Find middle: Fast/slow; when fast reaches the end, slow is at the last node of the first half. Set secondHead = slow.next, then slow.next = null to split.
- Reverse second half: Reverse the list starting at secondHead; get the new head of the reversed half.
- Merge: Two pointers: first at original head, second at the reversed second half head. While second is not null: save first.next and second.next, set first.next = second, second.next = saved first.next, advance first and second.
Example 1: Reorder List (In-Place)
Problem: You are given the head of a singly linked list. Reorder it to: L0 β Ln β L1 β Lnβ1 β L2 β β¦ Do not return anything; modify the list in-place.
function reorderList(head: ListNode | null): void {
if (head === null || head.next === null) return;
let slow: ListNode | null = head;
let fast: ListNode | null = head;
while (fast?.next?.next !== null) {
slow = slow!.next;
fast = fast.next.next;
}
let second = reverseList(slow!.next);
slow!.next = null;
let first: ListNode | null = head;
while (second !== null) {
const next1 = first!.next;
const next2 = second.next;
first!.next = second;
second.next = next1;
first = next1;
second = next2;
}
}
function reverseList(head: ListNode | null): ListNode | null {
let prev: ListNode | null = null;
let curr: ListNode | null = head;
while (curr !== null) {
const next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}- Time: O(n), Space: O(1).
Edge Cases
- Empty or single node β Return immediately; nothing to reorder.
- Two nodes β Middle is first node; second half has one node; merge gives L0 β L1 β null (already correct).
- Odd length β First half has one more node; when second is exhausted, first.next is already the rest of the first half; no extra work.
Common Mistakes
- Not splitting β Set slow.next = null so the first half and second half are truly separate before reversing.
- Merge order β Attach second to first, then second.next to the old first.next; then advance first = next1, second = next2.
- Loop condition β Merge while (second !== null); when second is shorter (odd length), first may have one node left; that node is already in place.
Time and Space Complexity
- Time: O(n) for find middle, reverse, and merge.
- Space: O(1).
Summary
- Reorder list: Find middle β split β reverse second half β merge first and reversed second alternately.
- Uses Find Middle, Reverse In-Place, and Fast and Slow Pointers. Related: Palindrome Linked List (same middle + reverse, then compare instead of merge).