题目描述
给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
分析
输入:链表头节点 head
输出:链表入口节点 / null
解题思路
这道题的关键在于两点:有没有环;若有,环的入口怎么找。
对于第一点,我们用快慢指针轻松证明~
对于第二点,我们做一些证明。
我们看官方的这张图。
对于 fast 走过的距离:a + n(b + c) + b = a + (n + 1)b + nc
对于 slow:a + b
因为存在一倍差距,所以可得: a + (n + 1)b + nc = 2a + 2b => a = (n - 1)(b + c) + c
所以如果不考虑绕多少圈,a = c,所以让 slow 节点 head 走到环入口和让 fast 从相遇的位置走到环入口的距离是一样的,我们可以据此得出,二者相遇时,都处在环入口节点,我们返回它即可
代码
/**
* 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
let slow = head
while (fast && fast.next) {
fast = fast.next.next
slow = slow.next
if (fast === slow) {
slow = head
while (fast !== slow) {
slow = slow.next
fast = fast.next
}
return slow
}
}
return null
}
复杂度
时间:O(N),需要遍历链表
空间:O(1),需要存储几个指针