某天深夜,程序员小明接到报警:链表王国发生一起离奇失踪案。一个链表节点在巡逻时突然消失,监控显示它在链表迷宫中反复绕圈。作为算法侦探,我们需要找到这个迷宫的入口,解救被困节点。
一、案发现场勘查
我们首先观察这个特殊链表的结构(如图示):
- 直线区段长度为 L(从头节点到环入口)
- 环形周长为 C(环内节点数量)
- 相遇点距入口 S 步(快慢指针相遇位置)
二、经典双指针破案法
2.1 第一轮追击:确认环形存在
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next; // 乌龟速度1
fast = fast.next.next; // 兔子速度2
if (slow === fast) { // 相遇点确认
// 进入第二轮定位
}
}
数学推导:
- 当兔子追上乌龟时,兔子跑过的距离是乌龟的2倍
- 设相遇时乌龟走了 K 步,则:
L + S = K
L + nC + S = 2K
解得:L = nC - S → L = (C - S) + (n-1)C
2.2 第二轮定位:寻找环形入口
let ptr = head;
while (ptr !== slow) {
ptr = ptr.next; // 新指针从起点出发
slow = slow.next; // 乌龟继续前进
}
return ptr; // 相遇点即为入口
关键证明:
根据第一轮推导结果,新指针走过 L 步到达入口时:
- 乌龟从相遇点出发走过 (C - S) 步
- 此时两者在入口处相遇:L = (C - S) + (n-1)C
三、复杂度分析
| 指标 | 数值 | 说明 |
|---|---|---|
| 时间复杂度 | O(N) | 线性遍历两次链表 |
| 空间复杂度 | O(1) | 仅使用固定数量指针 |
| 准确率 | 100% | 数学保证必然找到入口 |
四、案件还原实战演练
案例1:标准环形链表\
输入:1 → 2 → 3 → 4(4指向2)
推导:
- 第一轮相遇时:slow=2,fast=2
- 第二轮定位:ptr从1出发,slow从2出发
- 相遇点2即为入口
案例2:全环形链表\
输入:A → B → C → A
推导:
- 第一轮相遇点:B(A→B→C→A→B)
- 第二轮定位:ptr从A出发,slow从B出发
- 经过2步同时到达A点
五、高阶应用场景
- 内存泄漏检测:追踪对象引用环
- 无限循环识别:判断递归调用链
- 环形缓冲区优化:高效存储数据流
六、侦探笔记总结
- 核心思想:将环形问题转化为追击问题
- 关键公式:L = (C - S) + (n-1)C
- 代码要点:双指针速度差为2保证必然相遇
- 思维延伸:该算法思想可应用于各类循环检测
若将快指针速度改为3步/次,算法是否仍然有效?