链表解题框架
本节目标
用链表的连接关系而非节点值组织操作,掌握改向、合并、检测与定位边界的通用框架。
链表题的难点通常不是节点值,而是每次改写连接后,剩余结构是否还可达。先把“哪些节点已处理、下一步从哪里继续”说清楚,再选择指针,就能把看似零散的操作统一成稳定的框架。
识别信号
遇到以下特征时,应优先把数据看成一串节点和连接,而不是数组:
- 题目要求原地改变节点顺序、删除节点或拼接两条链;
- 需要处理头节点,而头节点本身可能被替换;
- 要判断节点能否再次访问,或从尾部定位某个节点;
- 节点除
next外还有额外指针,要求复制完整关系。
关键问题始终是:当前指针改向之前,后续入口是否已经被保存?
问题模型
链表不支持按下标随机访问,但每个节点都明确保存了它的后继。解题时先给每个指针一个职责:
prev、cur、nxt用于把当前节点的指向改到已处理部分;- 虚拟头节点把“原头节点被删除或还未确定”的分支统一为普通后继操作;
tail始终指向已合并结果的末尾;slow、fast以不同速度行进,用于检测环或维持固定间距。
这些指针都不是额外的技巧,而是把链表边界显式化:已完成部分、待处理部分,以及二者之间唯一能继续访问的位置。
通用模板
指针改向
改写一条 next 前,先保存旧后继:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
这正是反转链表的核心,也适用于局部反转等需要重接边的题目。
虚拟头节点与合并
当结果头节点可能变化时,先建立 dummy -> head。删除头节点、合并两条链表时,都只需修改某个节点的 next,无需单独处理“第一个节点”。合并时让 tail 接上当前较小节点,最后一次性接上未耗尽的链表。
快慢指针
fast 每轮两步、slow 每轮一步时,二者在有环链表中必然相遇。另一种用法是先让 fast 领先固定步数,再同步前进;当 fast 到尾部时,slow 就停在倒数位置的前驱。
母题序列
建议按必学顺序练习:
- 反转链表 必学:先建立改写指针前保存后继的习惯。
- 合并两个有序链表 必学:用虚拟头节点和
tail消除结果首节点分支。 - 环形链表 必学:从相对速度理解快慢指针的相遇。
- 删除链表的倒数第 N 个结点 必学:把固定间距与虚拟头节点组合起来处理删除边界。
常见误区
- 先覆盖
cur.next,再寻找后续节点,导致未处理链表丢失。 - 删除头节点时单独写一套分支,遗漏空链表或单节点边界。
- 合并时只移动输入指针,忘记同步推进结果链表的
tail。 - 把“相遇”误解为必须从同一个起点出发;环检测依赖的是相对速度。
- 用节点值判断节点身份。值可重复,链表关系必须按节点对象本身维护。
迁移方向
在基础操作稳定后,可继续练习随机链表的复制:它要求把节点对象与 next、random 两类关系一起复制;以及合并 K 个升序链表:它把两条链表的当前候选扩展为多个候选源的最小值选择。