算法_剖析环形链表之判断链表是否有环(II)

104 阅读2分钟

环形链表(II)

题目

力扣的142题,上一题只是判断链表是否有环就可以了,这题是有环的话就要返回开始入环的第一个节点,否则返回null.
原题如下:

image.png

分析一波

结合下图:

image.png
思路: 还是使用快慢指针。
有个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就可以啦。