[路飞]_leetcode刷题_142. 环形链表 II

122 阅读2分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

题目_142. 环形链表 II

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

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

不允许修改 链表。

思路:
申明一个存储空间,访问每一个节点,如果数组中没有这个节点,那么就将他放进这个数组,如果遇到存储空间中有这个节点,那么则判断该链表有环,并返回这个重复节点即可。
这里存储空间可以用数组,也可以用Set和Map。

暴力解法代码

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    let temp = new Set();
    let cur = head;
    while(cur){
        if(temp.has(cur)){
            return cur;
        }
        temp.add(cur);
        cur = cur.next;
    }
    return null;
};

双指针解法

思路:

首先看下图

建立两个指针fast和slow,fast每次走两步,slow每次走一步,假设两者在fast入环n圈之后相遇在如图bc中间紫色的点,那么可以得出

slow走过距离为a+b
fast走过距离为a+n(b+c)+b

又因为fast的速度为slow的两倍,则有如下等式
2(a+b) = a+n(b+c)+b => a = c + (n-1)(b+c)

那么我们发现当两个指针相遇的时候,再创建一个指针test,他每次走一步,当test和slow相遇的时候,那个位置就刚好是入环点

这里解法理解起来,主要就是要先找到上面这个等量公式,然后想明白即可。

题解代码

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