题目描述
删除链表的倒数第 n 个结点,返回头结点。
思路解析
先遍历数出长度,再从头走 len−n 步找到待删节点的前驱——要走两趟。能不能一趟搞定?让两个指针拉开 n 的固定间距。
fast 先独自走 n 步,于是 fast 比 slow 领先 n 个节点。然后两个一起走,当 fast 到达最后一个节点时,slow 正好落在「倒数第 n 个」的前一个,删它就方便了。
起点 · slow=fast=头:slow、fast 都从头出发。
fast 先走 n=2 步:fast 单独走 2 步到 3,slow 还在 1。两者间距 = n = 2,这个间距之后会一直保持。
同步走 · slow→2, fast→4:现在两个一起走一步:slow 到 2,fast 到 4。间距仍是 2。
fast 到尾 · slow 在待删前一个:再走一步:slow 到 3,fast 到最后一个 5(fast.next=null,停)。slow 停在 3,它的下一个 del=4 正是倒数第 2 个——要删的就是它。
删除 · slow.next = slow.next.next:执行 slow.next = slow.next.next:把 4 摘掉(虚线划掉),3 的箭头越过它直接接到 5。链表变成 1 → 2 → 3 → 5。
让两个指针保持 n 的间距一起走,领头的到尾、跟随的就到了「倒数第 n」的位置——这把「从后数」巧妙转成了「一起走到头」。
参考代码(Python)
1dummy = ListNode(0, head) # 哨兵,防删的是头结点
2slow = fast = dummy
3for _ in range(n): fast = fast.next # fast 先走 n 步
4while fast.next: # 同速走到尾
5 slow = slow.next; fast = fast.next
6slow.next = slow.next.next # 摘除
7return dummy.next复杂度分析
- 时间复杂度:O(n) —— 一趟扫描
- 空间复杂度:O(1) —— 两个指针
套路模板
记住骨架:哨兵 + fast 先走 k 步 + 同步到尾,slow 就停在倒数第 k 的前驱。删除、找倒数第 k 个都套它。
1dummy = ListNode(0, head) # 删除类先挂哨兵
2slow = fast = dummy
3for _ in range(k): fast = fast.next # 先拉开 k 的间距
4while fast.next: # 一起走到尾
5 slow, fast = slow.next, fast.next
6# 此时 slow 在倒数第 k 个的前一个易错点
- ❌ 不加哨兵,删头时崩 → ✅ 用 dummy 指向 head(删的是头结点时没有"前驱",哨兵补上这个前驱)
- ❌ fast 走 n 还是 n+1 步搞混 → ✅ 从 dummy 出发走 n 步(基准点不同步数差 1,最易错)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。