Reverse Linked List II — In-Place Partial Reversal Explained
Advertisement
Problem Statement
LeetCode 92 — Reverse Linked List II Difficulty: Medium | Pattern: Partial In-Place Reversal
Given the head of a singly linked list and two integers left and right where left <= right, reverse the nodes of the list from position left to position right, and return the reversed list. The list is 1-indexed.
Constraints:
- Number of nodes:
1 <= n <= 500 -500 <= Node.val <= 5001 <= left <= right <= n
Example 1:
Input: head = [1, 2, 3, 4, 5], left = 2, right = 4
Output: [1, 4, 3, 2, 5]Example 2:
Input: head = [5], left = 1, right = 1
Output: [5]Example 3:
Input: head = [3, 5], left = 1, right = 2
Output: [5, 3]Why This Problem Matters
Reverse Linked List II is one of the most instructive pointer manipulation problems in the entire LeetCode catalog. Facebook, Microsoft, and Amazon ask it in phone screens and onsite interviews because it tests not just whether you understand reversal, but whether you can precisely manage multi-pointer state while reversing only a subrange — leaving the rest of the list intact.
The full reversal (LC 206) is taught as a warm-up exercise. The partial reversal forces you to think carefully about how to reconnect the reversed segment to the unmodified head and tail of the list. Getting this wrong — even by one pointer assignment — produces incorrect output that is difficult to debug without drawing the state.
In practice, partial list reversal appears in network routing algorithms, undo buffers, and text editor data structures (rope structures). Any time you need to rearrange a contiguous segment of a sequence in-place, this is the template.
The elegant one-pass solution uses a technique called "front insertion" — moving nodes one by one to the front of the segment being reversed, without needing separate arrays or multiple traversals. This is a key pattern that also appears in the "Reverse Nodes in k-Group" problem (LC 25).
The Core Insight
The key insight is front insertion reversal: instead of reversing the segment and then reconnecting, you maintain a fixed prev pointer (the node before the reversal zone) and repeatedly move the first node of the remaining segment to become the new head of the reversed portion.
Concretely:
- Advance
prevto the node just before positionleft. This is the anchor. - Let
currbe the first node in the reversal zone (prev.next). - Repeat
right - lefttimes: movecurr.nextto the front of the reversed segment by inserting it afterprev.
This elegant trick avoids the need to track the "end" of the reversed segment separately — curr naturally falls to the tail of the reversed zone after all insertions.
Using a dummy head node eliminates the edge case where left = 1 (reversal starts at the head).
Visual Dry Run
Input: [1, 2, 3, 4, 5], left=2, right=4
Initial: dummy -> 1 -> [2 -> 3 -> 4] -> 5
prev = node(1), curr = node(2)Iteration 1 (move node(3) after prev):
nxt = curr.next = node(3)
curr.next = nxt.next = node(4)
nxt.next = prev.next = node(2)
prev.next = nxt = node(3)
State: dummy -> 1 -> 3 -> 2 -> 4 -> 5Iteration 2 (move node(4) after prev):
nxt = curr.next = node(4)
curr.next = nxt.next = node(5)
nxt.next = prev.next = node(3)
prev.next = nxt = node(4)
State: dummy -> 1 -> 4 -> 3 -> 2 -> 5Done — 2 iterations for right - left = 4 - 2 = 2.
Solution (Optimal)
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverseBetween(head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
prev = dummy
# Step 1: Advance prev to node just before position 'left'
for _ in range(left - 1):
prev = prev.next
# Step 2: Front insertion — repeat (right - left) times
curr = prev.next
for _ in range(right - left):
nxt = curr.next # node to move
curr.next = nxt.next # remove nxt from its position
nxt.next = prev.next # nxt points to current front of reversed segment
prev.next = nxt # nxt becomes new front of reversed segment
return dummy.nextfunction reverseBetween(head, left, right) {
const dummy = { val: 0, next: head };
let prev = dummy;
// Step 1: Advance prev to node before position 'left'
for (let i = 0; i < left - 1; i++) {
prev = prev.next;
}
// Step 2: Front insertion reversal
let curr = prev.next;
for (let i = 0; i < right - left; i++) {
const nxt = curr.next;
curr.next = nxt.next;
nxt.next = prev.next;
prev.next = nxt;
}
return dummy.next;
}Complexity:
| Metric | Value |
|---|---|
| Time | O(n) — single pass |
| Space | O(1) — in-place, no extra data structures |
Common Mistakes
- Not using a dummy head: Without a dummy, the case where
left = 1requires special handling to update the head pointer. Always use a dummy to make the code uniform. - Off-by-one in initial advance: The loop to advance
prevshould runleft - 1times (notleft). After the loop,prevshould be at positionleft - 1. - Wrong number of front insertions: The front insertion loop runs
right - lefttimes (notright - left + 1). The first node of the zone (curr) is already in its "reversed" position; you only need to moveright - leftmore nodes. - Incorrect pointer order in front insertion: The four pointer assignments must happen in this exact order: capture
nxt, updatecurr.next, updatenxt.next, updateprev.next. Changing the order corrupts the list. - Testing only on normal cases: Always test with
left = 1(reversal includes the head),left = right(single-node range, no-op), andright = n(reversal includes the tail).
Interview Tips
- Draw the before/after state: Show the list before reversal and what it should look like after. This demonstrates you understand the problem before writing code.
- Explain the front insertion technique: "Instead of reversing the segment first and reconnecting, I move nodes one at a time to the front of the reversed portion. This handles everything in one pass."
- Name the invariant: "After each iteration, the segment from
prev.nexttocurris reversed.curralways points to the node that will next enter the reversal zone." - Walk through the pointer assignments: Do not just write the four lines — verbalize each one. This is where candidates lose points when they have an order bug.
- Offer the two-pass alternative: Mention that you could reverse the segment separately and then reconnect, but it requires tracking more pointers and is more error-prone.
Follow-up Questions
- LeetCode 25 — Reverse Nodes in k-Group: Applies the same front insertion technique to groups of k nodes repeatedly.
- What if you needed to reverse multiple non-overlapping ranges? Apply the same algorithm once per range, using the returned head of each operation.
- Can you do it recursively? Yes, though recursion adds O(n) stack space. Discuss the tradeoff.
- What if left = right? Zero front insertions are performed — the list is unchanged. The algorithm handles this correctly.
- Reverse the entire list using this method: Set left=1 and right=n. Works perfectly with the dummy head approach.
- LeetCode 206 — Reverse Linked List: The simpler full-reversal version. Make sure you can solve both in the same interview.
Key Takeaways
- Use a dummy head to eliminate the special case where the reversal starts at position 1.
- The front insertion technique reverses the segment in one pass: repeatedly move
curr.nextto immediately afterprev. - The initial advance loop runs
left - 1times; the reversal loop runsright - lefttimes. - The four pointer assignments in each iteration must follow a strict order — capturing
nxtfirst prevents losing the reference. - This pattern directly extends to LC 25 (Reverse Nodes in k-Group), one of the most frequently asked hard linked list problems.
- Time is O(n) and space is O(1) — optimal for this problem and the expected answer in any FAANG interview.
Advertisement