链表核心操作
链表所有错都从一句话来:改 cur.next 之前,先把 cur.next 存下来,否则后面那一截就丢了。记住这句,再配 dummy / 双指针 / 头插反转三招,80% 链表题就是模板题。
直觉 — 断开前先保存 next
链表和数组最大的区别: 数组随便改一个位置, 别的元素不会消失; 链表你改了 cur.next, 原来那条链就立刻断了, 没有第二条路再走回去。
1 | |
所以模板的第一行永远是 nxt = cur.next。三步口诀:
- 存 —
nxt = cur.next(救命绳) - 转 —
cur.next = prev(动手术) - 移 —
prev = cur; cur = nxt(往前挪)
下面动画把这三步在 5 节点链表上演示一轮。重点盯三个指针: 黄色 cur、青色 prev、红色 nxt。每点一次”下一步”,看哪个箭头翻向了哪边。红色 nxt 出现的那一帧,就是”存”在救你命。
三大套路 — dummy / 双指针 / 头插反转
1. dummy 头节点 — 头会变就用它
凡是头节点可能被删/换/合的题(反转、合并、删除、分组),开局就 dummy = ListNode(0, head),最后返回 dummy.next。代价: 多一个节点。收益: 不写 if head is None 也不写 if node == head 的特判。
什么时候不用: 只遍历、只改值、不动结构(比如统计长度、找中点)。
2. 双指针 — 一招吃三题
| 场景 | 配方 |
|---|---|
| 找中点 | slow 走 1 步, fast 走 2 步, fast 到尾 → slow 在中间 |
| 检测环 | slow 1 步、fast 2 步, 相遇 = 有环, 永远碰不上 = 无环 |
| 倒数第 k 个 | fast 先走 k 步, 然后两者同步走, fast 到尾 → slow 在倒数第 k |
为什么有效: 两个指针速度差让”距离”成了可以利用的量。找中点是用”2 倍速到尾”换”1 倍速到半”,倒数第 k 是用”领先 k 步”换”落后 k 个位置”。
3. 头插法反转 — 不只反转链表
1 | |
每次把当前节点摘下来塞到 dummy 后面, 自动倒序。反转一段区间(LC 92)、K 个一组反转(LC 25) 都是这套头插的变体。
模板 — Python
反转整条链表:
1 | |
合并两个有序链表:
1 | |
检测环 + 找入口(Floyd):
1 | |
Floyd 环检测背后的数学
为什么”相遇后,一个回起点同速走,再次相遇即是入口”? 一张图能讲清:
1 | |
设起点到入口距离
相遇时:
- slow 走了
- fast 走了
(在环里多绕了 圈) - fast 速度是 slow 两倍:
化简:
翻译: 从起点走
记住一句: a = c (mod L)。剩下的全靠肌肉记忆。
经典题
热身(纯模板):
- LC 206. Reverse Linked List — 反转模板
- LC 21. Merge Two Sorted Lists — dummy + tail
- LC 876. Middle of the Linked List — 快慢指针
- LC 141. Linked List Cycle — Floyd 判环
- LC 83. Remove Duplicates from Sorted List — 单指针扫一遍
进阶(套路组合):
- LC 142. Linked List Cycle II — Floyd 找入口,上面数学的直接应用
- LC 19. Remove Nth Node From End — dummy + 双指针拉开 n 步
- LC 92. Reverse Linked List II — 头插法反转区间
- LC 25. Reverse Nodes in k-Group — 先数 k 个再反转,头插法变体
- LC 143. Reorder List — 找中点 + 反转后半 + 合并
- LC 148. Sort List — 找中点 + 归并
- LC 146. LRU Cache — 双向链表 + HashMap
判回文不开数组: 找中点 → 反转后半 → 双指针对比。三个核心操作一题用全。
记忆法
一句话: 改指针之前先存 next, 头会变就上 dummy, 想找位置就开俩指针。
三个对仗:
| 问题 | 套路 |
|---|---|
| 头节点可能变 | dummy |
| 要找”半路上”的位置 | 双指针(速度差或距离差) |
| 要倒序 / 反转一段 | 头插法到 dummy 后面 |
Floyd 环检测就背一句: a = c (mod L) — 起点到入口 = 相遇点到入口(模环长)。剩下的就是动手画图。链表题不画图直接写指针 = 必错,这条铁律永远不要破。