Linked List In-Place Reversal: Building Intuition¶
API Kernel:
LinkedListInPlaceReversalCore Insight: Reverse direction by changing where arrows point, not by moving data.
The Mental Model: Flipping Train Cars¶
Imagine a train where each car has a coupler pointing to the next car:
To reverse the train, you don't physically move the cars. Instead, you flip the direction of each coupler:
The Caboose becomes the new Engine (new head), and the original Engine points to nothing (new tail).
The Three-Pointer Dance¶
At each step, you work with three positions:
prev curr next_node
β β β
(reversed) β [ A ] <- [ B ] -> [ C ] -> (to process)
Action:
1. Save next_node = curr.next (or we lose C forever!)
2. Flip: curr.next = prev (B now points backward to A)
3. Advance prev = curr (prev moves to B)
4. Advance curr = next_node (curr moves to C)
It's like a caterpillar inching forward while flipping tracks behind it.
Visual Intuition: The Domino Effect¶
Full List Reversal (LC 206)¶
Think of dominoes standing in a row. To reverse them, you tip each one backward instead of forward:
Step 0: Stand behind first domino
ββββββββββ (all pointing right)
Step 1: Tip first one left (into empty space)
ββ ββββββββ
Step 2: Tip second one into first
ββββ ββββββ
Step 3: Continue...
ββββββ ββββ
Step 4: ...until done
ββββββββββ
The last domino becomes the "head" of the reversed sequence.
Segment Reversal (LC 92)¶
Same idea, but you only flip dominoes in a specific range:
Original: βββββββββββ (positions 1-6)
Reverse 2-4: ββ ββββββ ββββ
You need to:
1. Walk to position 1 (before the segment)
2. Remember this anchor point
3. Flip dominoes 2,3,4
4. Reconnect: anchorβ4, and 2β5
K-Group Reversal (LC 25)¶
Like reversing sections of a marching band, k musicians at a time:
Original (k=2): [1,2] [3,4] [5]
After groups: [2,1] [4,3] [5]
For each group:
1. Check: are there k musicians available?
2. If yes: flip their order
3. If no: leave them (the lonely 5 stays)
4. Move to next group
Why Three Pointers?¶
Consider reversing just one link without helpers:
The moment you flip curr.next, you've severed the connection to everything after curr. That's why you MUST save curr.next first:
# CORRECT
next_node = curr.next # Save the bridge before burning it
curr.next = prev # Now safe to flip
This is the most common bug in reversal problems!
The Dummy Node Trick¶
When you might change the first node, anchor to a fake "pre-head":
Without dummy (dangerous when left=1):
head β [ ] β [ ] β [ ]
What do we return if head changes?
With dummy (safe):
dummy β head β [ ] β [ ]
dummy.next is always the true head, even after changes!
Rule of thumb: If the head might move, use a dummy.
Segment Reversal: The Bookmark Pattern¶
For reversing a middle portion, think of bookmarking a book:
Book (list): [ Cover | Pages 1-5 | Pages 6-10 | Pages 11-15 | Back ]
To reverse pages 6-10:
1. Put bookmark BEFORE page 6 (after page 5)
2. Take out pages 6-10
3. Reverse them: 10-9-8-7-6
4. Reinsert: bookmark β page 10, and page 6 β page 11
In code: - before_segment = the bookmark (node before left) - segment_start = first page to reverse (becomes tail after) - prev after reversal = last page reversed (becomes head) - curr after reversal = first page NOT reversed (page 11)
K-Group: The Assembly Line¶
Imagine a factory assembly line with stations processing k items at a time:
Conveyor belt: [1][2][3][4][5][6][7]
Station 1 (k=3): Take [1][2][3], reverse to [3][2][1], pass on
Conveyor belt: [3][2][1][4][5][6][7]
Station 2 (k=3): Take [4][5][6], reverse to [6][5][4], pass on
Conveyor belt: [3][2][1][6][5][4][7]
Station 3 (k=3): Only [7] left (< 3), leave as-is
Final: [3][2][1][6][5][4][7]
The key insight: check availability BEFORE processing each group.
Common Pitfalls & Fixes¶
Pitfall 1: Losing the Next Node¶
# WRONG
curr.next = prev
curr = curr.next # Oops, curr.next is now prev!
# FIXED
next_node = curr.next
curr.next = prev
curr = next_node
Pitfall 2: Returning Wrong Head¶
# WRONG
return head # head is still the original first node (now tail)
# FIXED
return prev # prev is the new head after loop ends
Pitfall 3: Off-By-One in Segment¶
# WRONG: Starting from head when left=2
for _ in range(left): # Goes one too far!
before = before.next
# FIXED: Navigate left-1 times from dummy
for _ in range(left - 1):
before = before.next
Pitfall 4: Forgetting Reconnection¶
# WRONG: Reversed segment is now floating!
# ... reversal code ...
return dummy.next # Lost connection!
# FIXED: Reconnect both ends
segment_start.next = curr # old head β after segment
before_segment.next = prev # before β new head
Complexity Guarantees¶
| Variant | Time | Space | Key Factor |
|---|---|---|---|
| Full Reversal | O(N) | O(1) | Visit each node once |
| Segment Reversal | O(N) | O(1) | Navigate + reverse subset |
| K-Group Reversal | O(N) | O(1) | Each node: 1 count + 1 reverse |
| Recursive Variants | O(N) | O(N) or O(N/k) | Call stack depth |
The iterative versions are strictly O(1) space because we only use a fixed number of pointer variables, regardless of input size.
Pattern Recognition Checklist¶
When you see a linked list problem, ask:
- Does it mention "reverse"? β This pattern
- "Without extra space"? β Must be in-place (not array copy)
- "Swap adjacent pairs"? β K-group with k=2
- "Reverse between positions"? β Segment reversal
- "Reverse every k nodes"? β K-group reversal
If yes to any, reach for the three-pointer technique!