feat(patterns): pointer/array tutorials

This commit is contained in:
2025-08-18 22:15:43 +01:00
parent 7fd9e2a632
commit f2e4149e52
4 changed files with 1097 additions and 0 deletions

View File

@@ -0,0 +1,279 @@
name: LinkedList In-Place Reversal
slug: linkedlist-reversal
difficulty_level: 2
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: []