Linked Lists
Singly & Doubly Linked · Fast & Slow Pointers · Reversal · Merge · Cycle Detection — pointer manipulation patterns that appear in 30% of interview problems.
Section 1 — What Is a Linked List?
A linked list is a linear data structure where each element (node) stores a value and a pointer to the next node. Unlike arrays, nodes are not stored contiguously in memory — they can be scattered anywhere on the heap, connected only by pointers.
1.1 — Node Structure
1.2 — Complexity vs Arrays
- Access by index: O(n) — must traverse from head. (Arrays: O(1))
- Search: O(n) — both structures
- Insert/Delete at known position: O(1) — just rewire pointers. (Arrays: O(n) — must shift)
- Insert/Delete at unknown position: O(n) — must find position first
- Memory: Extra pointer per node. No wasted capacity like dynamic arrays.
Section 2 — Pattern: Fast & Slow Pointers (Floyd's Algorithm)
Two pointers move through the list at different speeds — fast moves 2 nodes per step, slow moves 1. They meet at meaningful positions.
Find Middle
When fast reaches end, slow is at middle. Use for palindrome check, merge sort on linked list.
Cycle Detection
If fast and slow meet, there's a cycle. If fast hits nullptr, no cycle.
Kth from End
Advance fast k steps first, then move both. When fast hits null, slow = kth from end.
// Cycle detection (Floyd’s) ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; // cycle detected } return false;
// Kth node from end (two-pointer with gap k) ListNode *fast = head, *slow = head; for (int i = 0; i < k; i++) fast = fast->next; // advance fast by k while (fast) { slow = slow->next; fast = fast->next; } // slow = kth node from end
</div>
<div class="ch-cplx-row">
<span class="ch-cplx"><span>Time</span>O(n)</span>
<span class="ch-cplx"><span>Space</span>O(1)</span>
</div>
</div>
<div class="chapter-section">
<h2 class="section-heading">Section 3 — Pattern: Reversal</h2>
<p>Reversing a linked list is O(n) time, O(1) space. Requires tracking three pointers: prev, curr, and next.</p>
<div class="insight-box">
<span class="insight-label">The 3-Pointer Dance</span>
Before breaking the link curr→next, save next first. Then redirect curr→prev. Advance: prev=curr, curr=next. Repeat until curr=nullptr. Return prev (new head).
</div>
<div class="ch-code-wrap">
```cpp
// Reverse entire list — iterative (preferred)
ListNode* reverseList(ListNode* head) {
ListNode *prev = nullptr, *curr = head;
while (curr) {
ListNode* nxt = curr->next; // save next
curr->next = prev; // redirect
prev = curr; // advance prev
curr = nxt; // advance curr
}
return prev; // new head
}
// Reverse a sublist from position left to right
// (0-indexed) — use dummy node + find boundaries
ListNode dummy(0); dummy.next = head;
ListNode* pre = &dummy;
for (int i = 0; i < left-1; i++) pre = pre->next; // node before sublist
ListNode* curr = pre->next;
for (int i = 0; i < right-left; i++) {
ListNode* nxt = curr->next;
curr->next = nxt->next;
nxt->next = pre->next;
pre->next = nxt;
}
return dummy.next;
Section 4 — Pattern: Dummy Node
Adding a dummy node before the head eliminates edge-case handling for empty lists or removing the head node. Always return dummy.next as the real head.
dummy.next at the end, not head — the head may have been removed or changed.
// Delete node with specific value — dummy prevents head case ListNode dummy(0); dummy.next = head; ListNode* curr = &dummy; while (curr->next) { if (curr->next->val == val) curr->next = curr->next->next; else curr = curr->next; } return dummy.next;
</div>
</div>
<div class="chapter-section">
<h2 class="section-heading">Section 5 — Pattern: Merge Two Sorted Lists</h2>
<p>Compare heads of both lists. Take the smaller one, advance that pointer. Use a dummy node to avoid edge cases.</p>
<div class="ch-code-wrap">
```cpp
// Merge two sorted linked lists — O(m+n) time, O(1) space
ListNode dummy(0); ListNode* tail = &dummy;
while (l1 && l2) {
if (l1->val <= l2->val) { tail->next = l1; l1 = l1->next; }
else { tail->next = l2; l2 = l2->next; }
tail = tail->next;
}
tail->next = l1 ? l1 : l2; // attach remaining
return dummy.next;
Section 6 — Hard Pattern: Reorder List
Combines multiple patterns: find middle (fast/slow), reverse second half, then merge two halves. L0→L1→…→Ln becomes L0→Ln→L1→Ln-1→L2→…
Practice Problems
| # | Problem | Pattern | Diff |
|---|---|---|---|
| 1 | 876. Middle of the Linked List | Fast/Slow | Easy |
| 2 | 83. Remove Duplicates from Sorted List | Traversal + pointer redirect | Easy |
| 3 | 206. Reverse Linked List | Reversal (iterative) | Easy |
| 4 | 92. Reverse Linked List II | Reversal (sublist) | Medium |
| 5 | 141. Linked List Cycle | Fast/Slow cycle detection | Easy |
| 6 | 21. Merge Two Sorted Lists | Merge + dummy node | Easy |
| 7 | 19. Remove Nth Node From End of List | Dummy + two-pointer gap | Medium |
| 8 | 2. Add Two Numbers | Simultaneous traversal + carry | Medium |
| 9 | 143. Reorder List | Three-part: mid + reverse + merge | Medium |
| 10 | 146. LRU Cache | Doubly linked list + HashMap | Medium |
| 11 | 23. Merge K Sorted Lists | K-way merge (min-heap) | Hard |