题目链接
题目描述
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
分析
可令快慢指针fast, slow同时从head出发,fast每次前进 2 个节点,slow前进 1 个。若链表有环,则两指针必定相遇。
图示如下:
假设 起始节点 到 入环节点 间的距离为 a,入环点 到 相遇点 间的距离为 b,环的 周长 为C,fast走过的总路程为S(fast),slow走过的总路程为S(slow)。
由图可知:
S(slow) = a + bS(fast) = a + b + kC,k为常数,且 k >= 1
又 S(fast) = 2 * S(slow),可得等式a + b + kC = 2 (a + b)
移项化简,可得: a = (k - 1)C + (C - b)
由此等式可知:从起始点走到入环点的距离a 与 从相遇点走k - 1圈再走到入环点的距离 相等
即:令两指针分别从 起始点 、快慢指针相遇点 出发,两指针每次都只走 1 步,最终 相遇时所在节点 即为 入环节点。
解法
- 令
fast,slow两指针同时从head出发 - 若
fast走到了null则证明无环。 fast与slow相遇时,令新指针target = head,target与slow此后每次各向前走1步,两指针相遇时所在节点即为所求。
代码
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let fast = head,
slow = head,
target = head;
while(fast) {
fast = fast.next?.next;
slow = slow.next;
if(fast === slow) {
// 有环
while(slow !== target) {
slow = slow.next;
target = target.next;
}
return target;
}
}
// 无环
return null
};