跳到主要内容

链表解题框架

本节目标

用链表的连接关系而非节点值组织操作,掌握改向、合并、检测与定位边界的通用框架。

链表题的难点通常不是节点值,而是每次改写连接后,剩余结构是否还可达。先把“哪些节点已处理、下一步从哪里继续”说清楚,再选择指针,就能把看似零散的操作统一成稳定的框架。

识别信号

遇到以下特征时,应优先把数据看成一串节点和连接,而不是数组:

  • 题目要求原地改变节点顺序、删除节点或拼接两条链;
  • 需要处理头节点,而头节点本身可能被替换;
  • 要判断节点能否再次访问,或从尾部定位某个节点;
  • 节点除 next 外还有额外指针,要求复制完整关系。

关键问题始终是:当前指针改向之前,后续入口是否已经被保存?

问题模型

链表不支持按下标随机访问,但每个节点都明确保存了它的后继。解题时先给每个指针一个职责:

  • prevcurnxt 用于把当前节点的指向改到已处理部分;
  • 虚拟头节点把“原头节点被删除或还未确定”的分支统一为普通后继操作;
  • tail 始终指向已合并结果的末尾;
  • slowfast 以不同速度行进,用于检测环或维持固定间距。

这些指针都不是额外的技巧,而是把链表边界显式化:已完成部分、待处理部分,以及二者之间唯一能继续访问的位置。

通用模板

指针改向

改写一条 next 前,先保存旧后继:

nxt = cur.next
cur.next = prev
prev = cur
cur = nxt

这正是反转链表的核心,也适用于局部反转等需要重接边的题目。

虚拟头节点与合并

当结果头节点可能变化时,先建立 dummy -> head。删除头节点、合并两条链表时,都只需修改某个节点的 next,无需单独处理“第一个节点”。合并时让 tail 接上当前较小节点,最后一次性接上未耗尽的链表。

快慢指针

fast 每轮两步、slow 每轮一步时,二者在有环链表中必然相遇。另一种用法是先让 fast 领先固定步数,再同步前进;当 fast 到尾部时,slow 就停在倒数位置的前驱。

母题序列

建议按必学顺序练习:

  1. 反转链表 必学:先建立改写指针前保存后继的习惯。
  2. 合并两个有序链表 必学:用虚拟头节点和 tail 消除结果首节点分支。
  3. 环形链表 必学:从相对速度理解快慢指针的相遇。
  4. 删除链表的倒数第 N 个结点 必学:把固定间距与虚拟头节点组合起来处理删除边界。

常见误区

  • 先覆盖 cur.next,再寻找后续节点,导致未处理链表丢失。
  • 删除头节点时单独写一套分支,遗漏空链表或单节点边界。
  • 合并时只移动输入指针,忘记同步推进结果链表的 tail
  • 把“相遇”误解为必须从同一个起点出发;环检测依赖的是相对速度。
  • 用节点值判断节点身份。值可重复,链表关系必须按节点对象本身维护。

迁移方向

在基础操作稳定后,可继续练习随机链表的复制:它要求把节点对象与 nextrandom 两类关系一起复制;以及合并 K 个升序链表:它把两条链表的当前候选扩展为多个候选源的最小值选择。