Leetcode-面试题02.08-环路检测

308 阅读2分钟

面试题02.08-环路检测,如果用快慢指针来解题,那么本质是一道数学题。

使用快慢指针解题:

  1. 定义3个变量

    1. fast:快指针,每次走两步;
    2. slow:慢指针,每次走一步;
    3. rs:链表起始的位置;
  2. 如果链表有“环”那么fast与slow一定会在环里相遇,当fast === null 或者 fast.next === null 那么意味着,改链表没有环;

  3. 接下来我们求“环”的起点,首先我们先明确的几个点

    1. fast与slow的相遇永远是fast追上了slow
    2. 还要记住几个关键位置,“环”的起点,以及fast与slow相遇的位置
  4. 假设:当slow第一次走到“环”的起点时,需要走 a 步;那么这时候fast就会距离“环”起点 a 的地方,因为fast = 2倍slow;

  5. 当slow走到“环”的起点时,我们思考,fast什么时候能追上slow?fast是slow的两倍,那么每走一次fast就跟slow近了一步。

  6. 假设我们fast和slow同时走了X步,使得fast追上了slow,那么fast在“环”里走过的路程为 2x+a,这时候可能很多人会疑惑,算这个有什么用?回过头我们看slow,由于slow每次走了一步,那么这时候slow在环里走了已经x步,然而这时fast刚好在环里走了2x+a的路程,那么2x+a-x 就等于 x+a ,这也就意味着,从“环”的起点开始,每次走一步,走x+a步那么就会再次回到“环”的起点

  7. 这时候slow已经走了x步了,同时在继续走a步那么就能回到“环”的起始位置。恰好从头部开始往后走a步也能到达“环”的起始位置。

  8. 有了上述逻辑,那么我们先通过 fast === slow,找到fast与slow在环中相遇的位置,紧接着在使slow往后走,同时让rs从链表的头部开始走,每次走一步,一共走a步,那么他们必然在“环”的起始位置相遇时。

    // 上述8中的逻辑,rs从链表头部开始走,slow从环中与fast的相遇点往后走,两个人同时走一步,在a步后必然相遇。
    let rs = head
    while(rs !== slow){
      rs = rs.next;
      slow = slow.next;
    }
    return slow
    
/**
 * 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 ;
    if(head && head.next){
        do  {
                fast = fast.next.next;
                slow = slow.next;
            }  while((fast!==null && fast.next!==null) && (fast !== slow))
​
            if(fast===null || fast.next===null){
                return null
            }else{
                let rs = head
                while(rs !== slow){
                rs = rs.next;
                slow = slow.next;
                }
                return slow
            }
    }else{
        return null
    }
};

\