409 lines
12 KiB
YAML
409 lines
12 KiB
YAML
name: LinkedList In-Place Reversal
|
|
slug: linkedlist-reversal
|
|
difficulty_level: 2
|
|
pattern_type: technique
|
|
display_order: 14
|
|
|
|
description: >
|
|
Reverse linked list nodes in-place by manipulating pointers without allocating
|
|
extra space. This technique uses three pointers to track the previous, current,
|
|
and next nodes while systematically reversing the direction of links.
|
|
|
|
when_to_use: |
|
|
- Reversing an entire linked list
|
|
- Reversing a portion of a linked list
|
|
- Reversing in groups of K nodes
|
|
- Palindrome linked list verification
|
|
- Reordering list problems
|
|
|
|
metaphor: |
|
|
Imagine a conga line where everyone faces forward. To reverse it, you don't
|
|
rearrange people—you have each person turn around and grab the shoulders of
|
|
whoever was behind them. You process one person at a time: they turn around,
|
|
the next person steps forward, and so on until everyone faces the opposite direction.
|
|
|
|
Another analogy: reversing a chain of paper clips. You unclip each one from its
|
|
forward neighbor and clip it to its backward neighbor, working through the chain.
|
|
|
|
core_concept: |
|
|
Linked list reversal uses **three pointers** moving through the list:
|
|
|
|
- **prev**: Points to the already-reversed portion (starts as null)
|
|
- **curr**: The node currently being processed
|
|
- **next**: Temporarily stores the next node before we break the link
|
|
|
|
At each step:
|
|
1. Save `curr.next` in `next` (before we lose it)
|
|
2. Reverse the link: `curr.next = prev`
|
|
3. Advance: `prev = curr`, `curr = next`
|
|
|
|
The key insight is that we're not moving nodes—we're redirecting pointers.
|
|
This achieves O(n) time with O(1) space.
|
|
|
|
For **partial reversal** (reversing between positions m and n), we:
|
|
1. Navigate to position m-1 (the node before reversal starts)
|
|
2. Reverse nodes from m to n
|
|
3. Reconnect the reversed portion to the rest of the list
|
|
|
|
visualization: |
|
|
**Full list reversal:**
|
|
|
|
```
|
|
Initial: 1 → 2 → 3 → 4 → null
|
|
prev=null, curr=1
|
|
|
|
Step 1: Save next=2, reverse 1's link
|
|
null ← 1 2 → 3 → 4
|
|
prev curr
|
|
|
|
Step 2: Save next=3, reverse 2's link
|
|
null ← 1 ← 2 3 → 4
|
|
prev curr
|
|
|
|
Step 3: Save next=4, reverse 3's link
|
|
null ← 1 ← 2 ← 3 4
|
|
prev curr
|
|
|
|
Step 4: Save next=null, reverse 4's link
|
|
null ← 1 ← 2 ← 3 ← 4
|
|
prev curr=null
|
|
|
|
Result: 4 → 3 → 2 → 1 → null
|
|
```
|
|
|
|
**Partial reversal (positions 2 to 4):**
|
|
|
|
```
|
|
Initial: 1 → 2 → 3 → 4 → 5
|
|
positions: 1 2 3 4 5
|
|
|
|
Goal: 1 → 4 → 3 → 2 → 5
|
|
|
|
Step 1: Find node before position 2
|
|
before = node 1
|
|
|
|
Step 2: Reverse nodes 2, 3, 4
|
|
1 null ← 2 ← 3 ← 4 5
|
|
↑ ↑ ↑
|
|
before prev curr
|
|
|
|
Step 3: Reconnect
|
|
before.next.next = curr (2 → 5)
|
|
before.next = prev (1 → 4)
|
|
|
|
Result: 1 → 4 → 3 → 2 → 5
|
|
```
|
|
|
|
code_template: |
|
|
class ListNode:
|
|
def __init__(self, val=0, next=None):
|
|
self.val = val
|
|
self.next = next
|
|
|
|
|
|
def reverse_list(head: ListNode) -> ListNode:
|
|
"""Reverse entire linked list."""
|
|
prev = None
|
|
curr = head
|
|
|
|
while curr:
|
|
next_node = curr.next # Save next
|
|
curr.next = prev # Reverse link
|
|
prev = curr # Advance prev
|
|
curr = next_node # Advance curr
|
|
|
|
return prev # New head
|
|
|
|
|
|
def reverse_between(head: ListNode, m: int, n: int) -> ListNode:
|
|
"""Reverse nodes from position m to n (1-indexed)."""
|
|
if not head or m == n:
|
|
return head
|
|
|
|
dummy = ListNode(0)
|
|
dummy.next = head
|
|
before = dummy
|
|
|
|
# Move to node before reversal starts
|
|
for _ in range(m - 1):
|
|
before = before.next
|
|
|
|
# Reverse n - m + 1 nodes
|
|
prev = None
|
|
curr = before.next
|
|
for _ in range(n - m + 1):
|
|
next_node = curr.next
|
|
curr.next = prev
|
|
prev = curr
|
|
curr = next_node
|
|
|
|
# Reconnect
|
|
before.next.next = curr # tail of reversed → rest of list
|
|
before.next = prev # before → new head of reversed
|
|
|
|
return dummy.next
|
|
|
|
|
|
def reverse_k_group(head: ListNode, k: int) -> ListNode:
|
|
"""Reverse nodes in groups of k."""
|
|
# Count total nodes
|
|
count = 0
|
|
node = head
|
|
while node:
|
|
count += 1
|
|
node = node.next
|
|
|
|
dummy = ListNode(0)
|
|
dummy.next = head
|
|
before = dummy
|
|
|
|
while count >= k:
|
|
# Reverse k nodes
|
|
prev = None
|
|
curr = before.next
|
|
for _ in range(k):
|
|
next_node = curr.next
|
|
curr.next = prev
|
|
prev = curr
|
|
curr = next_node
|
|
|
|
# Reconnect
|
|
tail = before.next
|
|
tail.next = curr
|
|
before.next = prev
|
|
|
|
# Move to next group
|
|
before = tail
|
|
count -= k
|
|
|
|
return dummy.next
|
|
|
|
|
|
def reverse_list_recursive(head: ListNode) -> ListNode:
|
|
"""Reverse list using recursion."""
|
|
if not head or not head.next:
|
|
return head
|
|
|
|
new_head = reverse_list_recursive(head.next)
|
|
head.next.next = head # Reverse link
|
|
head.next = None # Prevent cycle
|
|
|
|
return new_head
|
|
|
|
recognition_signals:
|
|
- "reverse linked list"
|
|
- "reverse between"
|
|
- "reverse in groups"
|
|
- "reverse k-group"
|
|
- "palindrome linked list"
|
|
- "reorder list"
|
|
- "swap nodes"
|
|
- "rotate list"
|
|
|
|
common_mistakes:
|
|
- title: Losing reference to next node
|
|
description: |
|
|
Reversing `curr.next` before saving it means you can't advance to the
|
|
next node.
|
|
fix: |
|
|
Always save the next node first:
|
|
```python
|
|
next_node = curr.next # Save FIRST
|
|
curr.next = prev # Then reverse
|
|
```
|
|
|
|
- title: Forgetting to update connections in partial reversal
|
|
description: |
|
|
Reversing the middle portion without reconnecting it to the beginning
|
|
and end of the list breaks the list.
|
|
fix: |
|
|
After reversing, reconnect both ends:
|
|
```python
|
|
before.next.next = curr # tail → rest
|
|
before.next = prev # before → new head
|
|
```
|
|
|
|
- title: Not using a dummy node
|
|
description: |
|
|
When the reversal might include the head, handling the head separately
|
|
adds complexity and edge cases.
|
|
fix: |
|
|
Use a dummy node pointing to head. This simplifies edge cases:
|
|
```python
|
|
dummy = ListNode(0)
|
|
dummy.next = head
|
|
# ... reversal logic ...
|
|
return dummy.next
|
|
```
|
|
|
|
- title: Off-by-one with positions
|
|
description: |
|
|
Confusing 0-indexed vs 1-indexed positions causes reversal of wrong nodes.
|
|
fix: |
|
|
Clarify indexing convention. For 1-indexed positions, loop `m-1` times
|
|
to reach the node *before* position m.
|
|
|
|
variations:
|
|
- name: Full reversal
|
|
description: |
|
|
Reverse the entire linked list. Simplest form—just walk through and
|
|
reverse each link.
|
|
example: "Reverse Linked List"
|
|
|
|
- name: Partial reversal
|
|
description: |
|
|
Reverse only nodes between positions m and n. Need to track connection
|
|
points before and after the reversed section.
|
|
example: "Reverse Linked List II"
|
|
|
|
- name: K-group reversal
|
|
description: |
|
|
Reverse every k consecutive nodes. Often requires counting total nodes
|
|
first to know when to stop.
|
|
example: "Reverse Nodes in k-Group"
|
|
|
|
- name: Alternating reversal
|
|
description: |
|
|
Reverse every other group of k nodes. Combines k-group logic with
|
|
skip logic.
|
|
example: "Reverse Alternate K Nodes"
|
|
|
|
- name: Recursive reversal
|
|
description: |
|
|
Elegant recursive solution that reverses by relying on the recursive
|
|
call to reverse the rest, then fixing up the current node.
|
|
example: "Reverse Linked List (recursive approach)"
|
|
|
|
related_patterns:
|
|
- fast-slow-pointers
|
|
- two-pointers
|
|
|
|
prerequisite_patterns: []
|
|
|
|
visualization_examples:
|
|
- id: reverse-linked-list
|
|
title: Reverse Entire Linked List
|
|
input:
|
|
list: [1, 2, 3, 4]
|
|
code: |
|
|
def reverse_list(head):
|
|
prev = None
|
|
curr = head
|
|
|
|
while curr:
|
|
next_node = curr.next
|
|
curr.next = prev
|
|
prev = curr
|
|
curr = next_node
|
|
|
|
return prev
|
|
steps:
|
|
- id: step-1
|
|
description: "Initialize prev=None, curr=head (node 1)."
|
|
structures:
|
|
list:
|
|
type: linkedlist
|
|
nodes:
|
|
- { value: 1, state: active }
|
|
- { value: 2, state: default }
|
|
- { value: 3, state: default }
|
|
- { value: 4, state: default }
|
|
pointers:
|
|
curr: 0
|
|
variables:
|
|
prev: "null"
|
|
codeHighlight:
|
|
startLine: 2
|
|
endLine: 3
|
|
|
|
- id: step-2
|
|
description: "Save next=2, reverse link: 1→null. Move pointers forward."
|
|
structures:
|
|
list:
|
|
type: linkedlist
|
|
nodes:
|
|
- { value: 1, state: visited, annotations: ["→null"] }
|
|
- { value: 2, state: active }
|
|
- { value: 3, state: default }
|
|
- { value: 4, state: default }
|
|
pointers:
|
|
prev: 0
|
|
curr: 1
|
|
variables:
|
|
next_node: 2
|
|
codeHighlight:
|
|
startLine: 6
|
|
endLine: 9
|
|
|
|
- id: step-3
|
|
description: "Save next=3, reverse link: 2→1. Move pointers forward."
|
|
structures:
|
|
list:
|
|
type: linkedlist
|
|
nodes:
|
|
- { value: 1, state: visited, annotations: ["→null"] }
|
|
- { value: 2, state: visited, annotations: ["→1"] }
|
|
- { value: 3, state: active }
|
|
- { value: 4, state: default }
|
|
pointers:
|
|
prev: 1
|
|
curr: 2
|
|
variables:
|
|
next_node: 3
|
|
codeHighlight:
|
|
startLine: 6
|
|
endLine: 9
|
|
|
|
- id: step-4
|
|
description: "Save next=4, reverse link: 3→2. Move pointers forward."
|
|
structures:
|
|
list:
|
|
type: linkedlist
|
|
nodes:
|
|
- { value: 1, state: visited, annotations: ["→null"] }
|
|
- { value: 2, state: visited, annotations: ["→1"] }
|
|
- { value: 3, state: visited, annotations: ["→2"] }
|
|
- { value: 4, state: active }
|
|
pointers:
|
|
prev: 2
|
|
curr: 3
|
|
variables:
|
|
next_node: 4
|
|
codeHighlight:
|
|
startLine: 6
|
|
endLine: 9
|
|
|
|
- id: step-5
|
|
description: "Save next=null, reverse link: 4→3. curr becomes null, loop ends."
|
|
structures:
|
|
list:
|
|
type: linkedlist
|
|
nodes:
|
|
- { value: 1, state: visited, annotations: ["→null"] }
|
|
- { value: 2, state: visited, annotations: ["→1"] }
|
|
- { value: 3, state: visited, annotations: ["→2"] }
|
|
- { value: 4, state: found, annotations: ["→3", "new head"] }
|
|
pointers:
|
|
prev: 3
|
|
variables:
|
|
next_node: "null"
|
|
codeHighlight:
|
|
startLine: 11
|
|
endLine: 11
|
|
|
|
- id: step-6
|
|
description: "Return prev (node 4). Reversed list: 4→3→2→1→null"
|
|
structures:
|
|
reversed:
|
|
type: linkedlist
|
|
nodes:
|
|
- { value: 4, state: found, annotations: ["head"] }
|
|
- { value: 3, state: default }
|
|
- { value: 2, state: default }
|
|
- { value: 1, state: default }
|
|
variables:
|
|
result: "4→3→2→1→null"
|
|
codeHighlight:
|
|
startLine: 11
|
|
endLine: 11
|