环形链表(II)
题目
力扣的142题,上一题只是判断链表是否有环就可以了,这题是有环的话就要返回开始入环的第一个节点,否则返回null.
原题如下:
分析一波
结合下图:
思路:
还是使用快慢指针。
有个p,q指针,q是p速度的2倍,
假设p走到环的初始节点时的距离是a,
而q这时肯定已经走到环内了,q走的总距离为2a,
所以在环内刚好也走了a(至于已经走了几圈不重要),
那么再假设此时q距离环内剩余的距离为x,那么环的总长度为a+x;
如果这时候,p走了x 跟q相遇的话,那么q肯定走了2x,
妙的地方来了:
因此这时候相遇后,p和q在环内剩下的距离刚好为a(因为环总长度为a+x), a+x-x=a;
而头节点到环初始节点的距离也是a;
那么只要让一个指针从head那里开始走,同时让一个指针从环内p和q相遇的位置也以相同的速度也往前走,那么两个指针必定会在环的初始节点那相遇。
注意:
上面说的有环的情况下,如果没有环的话,那么p和q永远都不会相遇
实践,上代码分析
var detectCycle = function(head) {
if(!head) return null;
let p=head,q=head;
while(q&&q.next){
p=p.next;
q=q.next.next;
if(p===q){
p=head;
while(p!==q){
p=p.next;
q=q.next;
}
return p;
}
}
return null;
};
没有head的话,就直接返回null;
定义p和q节点都指向head;
利用一个循环,去走这个链表,没有q和q的下一个节点的话就退出,不然循环里面会报错;
让p走一步,q走两步,其实只要是个快慢指针就好了,两个的速度走几步随自己,我这里是用的2倍速;
如果p等于q,这时候两个指针就是在环内相遇了,否则就是没有环,返回null;
如果p等于q,只需让两个节点一个从head那里走过来,另一个从环内相遇的位置往前走,这样的对立面以相同的速度,肯定会在环的初始节点那里相遇;
这时候,我们让p节点等于head,以一步的速度从头节点那里往前走,而让q以一步的速度往前走,他两不相遇就一直往前走;
如果相遇了,就返回p就可以啦。