环形链表
如何判断链表是否有环?
- 做法:
slow走 1 步,fast走 2 步; - 有环: 两指针必在环内相遇 (相对速度 1, 环内距离持续缩小);
- 无环:
fast先到达null; - 时间 , 空间 ;
const hasCycle = (head) => {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
};
如何找到环的入口结点?
- 设: 头到入口为 , 入口到相遇点为 , 相遇点绕回入口为 ;
- 步数:
slow走 ;fast走 ; - 由 得 ;
- 取 时 : 从头与从相遇点各出发一个步长为 1 的指针, 相遇处即入口;

const detectCycle = (head) => {
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
let res = head;
while (res !== slow) {
res = res.next;
slow = slow.next;
}
return res;
}
}
return null;
};
数组中的重复数为什么等价于找环入口?
- 建模: 把
nums看成链表, 下标i是结点,nums[i]是它的next, 于是下一步是nums[nums[i]]; - 重复元素: 有两个下标指向同一结点, 该结点即环的入口;
- 结论: 直接套用找环入口的两段快慢指针;
- 注意: 不能改动数组 (否则可排序或标记下标);
const findDuplicate = (nums) => {
let slow = 0;
let fast = 0;
while (true) {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow === fast) break;
}
let finder = 0;
while (finder !== slow) {
slow = nums[slow];
finder = nums[finder];
}
return finder;
};