持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
leetcode 142. 环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
思路分析:
本题是一道算法题也可以说是一道数学题,首先我们解决这道题需要先确定里面链表里面是否有环存在,如果环存在的情况下,再去寻找环的入口,如何判断环是否存在呢,我们可以通过快慢指针的方式来确定,设置一个慢指针每次走一步,再设置一个快指针每次走两步,如果快慢指针能够相遇,那么就说明链表里面有环。
当我们确定链表里面有环之后,就可以开始寻找环的入口了,我们假设从head到环入口的距离是a,环入口到相遇点的距离是b,环剩余距离是c,因为快指针是慢指针的两倍速,所以当他们相遇时,慢指针走了a+b,快指针走了2*(a+b),那么就可以得出 2*(a+b)=a+(n+1)b+n*c
由此得知a=c+(n-1)(b+c)
因为快慢指针的速度差异得知,假设环为l,快慢指针最大距离l-1,慢指针需要l秒跑完一圈,而快指针每秒可以追1的距离,那么可以得知相遇时,慢指针还未跑过一圈。所以a等于c
那么我们再找到环的相遇点之后,让快指针回到head,并设置相同的速度,那么他们再次相遇时所在点就是环的入口。
实现代码:
var detectCycle = function(head) {
if(!head)return null
let slow = head
let fast = head
while(fast.next){
slow = slow.next
fast = fast.next.next
if(!fast) return null
if(fast===slow){
fast = head
while(slow!==fast){
slow = slow.next
fast = fast.next
}
return slow
}
}
return null
};