[路飞]_leetcode刷题_面试题 02.08. 环路检测

170 阅读3分钟

题目

面试题 02.08. 环路检测

给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

示例 1:

image.png

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

image.png

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

进阶:

  • 你是否可以不用额外空间解决此题?

思路1:

这一题之前在普通题库里做过,这里又遇到了,那就再做一遍。

  1. 用一个哈希表记录遍历过的节点如果节点在哈希表中,
  2. 遍历链表,如果节点在哈希表中,那么直接return该节点即可;如果不在哈希表中,则将节点放入哈希表。
  3. 遍历结束发现没有环,则返回null。

代码如下:

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    let hashMap = new Map();
    let cur = head;
    while(cur){
        if(!hashMap.has(cur)){
            hashMap.set(cur,null)
            cur = cur.next;
        }else{
            return cur
        }
    }
    return null;
};

思路2:

题目中写了进阶的要求,能否不使用额外的存储空间。

这里就想到了可以使用快慢指针的方法。

首先得明白这其中的数学原理。

image.png

  1. 假设一个fast指针每次向前走两步,一个slow指针每次向前走一步,两者同时出发,进入环后,一定会在环中某一点相遇。
  2. 由于fast速度是slow的两倍,当slow入环后,在一圈之内一定会被fast追上,这个仔细品一品。
  3. 假设两者在环中紫色的点相遇,那么slow走了a+b的距离,fast比slow多走n圈,一圈是b+c,那么fast走了a+b+n(b+c)
  4. 由于fast速度是slow的两倍,则可以得到等式 2(a+b)=a+b+n(b+c)
  5. 将等式化简一下,得到 a = (n-1)(b+c) + c

从这里我们可以得到什么启发呢?

就是假设两个节点分别从链表头紫色点开始走,每次走一步,那么会在相交点相遇

  1. 首先两个节点向前走,相遇这个过程,我们用代码是可以实现的
if(fast.next == slow.next){
    // 两者相遇
}else{
    slow = slow.next;
    fast = fast.next.next;
}
  1. 当两者在紫色点相遇的时候,我们新创建一个对比指针,一次走一步,那么当它两相遇的时候,返回这个相遇点即可

代码如下:

 /**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    if(head === null){
        return null;
    }
    let fast = head;
    let slow = head;
    while(fast !== null){
        slow = slow.next;
        if(fast.next){
            fast = fast.next.next;
        }else{
            return null
        };
        if(fast === slow){
            let test = head;
            while(slow !== test){
                slow = slow.next;
                test = test.next;
            }
            return test;
        }
    }
    return null;
};