题目描述
返回单链表的中间结点;若有两个中点(节点数为偶数),返回靠后的那个。
思路解析
先遍历一遍数出长度 n,再从头走 ⌊n/2⌋ 步定位中点——逻辑没错,但要把链表走两趟。能不能一趟就停在中间?
转折:fast 的速度正好是 slow 的两倍。所以当 fast 走完整条链(约 n 步)时,slow 只走了 n/2 步——天然停在中点。一趟就够,这就是「速度差定位」。
起点 · slow = fast = 头:slow 和 fast 都从头节点 1 出发,重合在一起。下面开始:每一轮 slow 走 1 步、fast 走 2 步,分开移动看得清楚。
第 1 轮 · slow 走 1 步:slow 慢慢来,先走 1 步:1 → 2。fast 暂时还停在头 1,等下它要走两步。
第 1 轮 · fast 走 2 步:fast 一口气走 2 步:1 → 2 → 3。本轮结束:slow 在 2、fast 在 3。fast 把 slow 甩开了,领先正好是 slow 走过距离的两倍。
判循环条件 · fast 后面还有节点:进下一轮前先看条件 while fast and fast.next:fast 在 3,它后面还有 4、5,条件成立,可以再走一轮。
第 2 轮 · slow 走 1 步:slow 走 1 步:2 → 3,来到链表正中。
第 2 轮 · fast 走 2 步到尾:fast 再走 2 步:3 → 4 → 5,落在最后一个节点。此刻 slow 在 3、fast 在 5。fast 想再跨两步就出界了。
fast 到尾 · 循环停 · slow 即中点:关键转折:fast 在 5,它的 next 是 null,循环条件 fast and fast.next 不成立、停止。fast 走完整条链时,slow 只走了一半——slow 正停在 3,返回它及其之后 3 → 4 → 5。
偶数个的情况 · 取靠后中点:反向想一下偶数个:若链表只有 1→2→3→4,fast 从头走 2 步到 3、再走 2 步到 null 停,slow 走到 3——返回靠后的那个中点。靠的就是条件 while fast and fast.next,奇偶两种它都处理好了。
快慢指针是链表的万能钥匙:2:1 速度差找中点;同速带固定间距找倒数第 k 个;fast 追 slow 判环。记住「两个指针不同步走」这一招。
参考代码(Python)
1def middleNode(self, head):
2 slow = fast = head
3 while fast and fast.next: # fast 还能安全跨两步
4 slow = slow.next # 慢走 1 步
5 fast = fast.next.next # 快走 2 步
6 return slow # fast 到尾,slow 在中点复杂度分析
- 时间复杂度:O(n) —— fast 走完整条链就停,只一趟
- 空间复杂度:O(1) —— 只用 slow、fast 两个指针,不存任何节点
套路模板
记住骨架:slow 走 1、fast 走 2、循环条件 fast and fast.next。判环、找环入口、回文链表都是从这个骨架变化而来。
1slow = fast = head
2while fast and fast.next: # 防 fast.next.next 越界
3 slow = slow.next # 1 步
4 fast = fast.next.next # 2 步
5# fast 到尾时,slow 在中点(偶数取靠后)易错点
- 错误写法:循环条件写成 while fast and fast.next.next → 正确写法:while fast and fast.next(它决定偶数时取前/后中点:写 fast and fast.next 取靠后(本题要的),写 fast.next and fast.next.next 才取靠前)
- 错误写法:循环条件只写 while fast → 正确写法:while fast and fast.next(fast.next 为空时再 .next.next 会空指针报错)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。