【LeetCode】画个图带你玩转环形链表II

418 阅读2分钟

嗨!~ 大家好,我是YK菌 🐷 ,一个微系前端 ✨,喜欢分享自己学到的小知识 🏹,欢迎关注我呀 😘 ~ [微信号: yk2012yk2012,微信公众号:ykyk2012]

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

昨天我们刷了一道环形链表,今天我们来一道环形链表II

142. 环形链表 II

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

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/li…

【解法一】使用Map

和上一题一样,直接使用 Map 的解法,保存遍历过的结点,遇到第一个遍历过的就返回它

var detectCycle = function(head) {
    let map = new Map()
    while(head){
        if(map.has(head)){
            return head;
        }
        map.set(head, true)
        head = head.next
    }
    return null
};

虽然可以解决问题,但是效率还是太低了

image.png

【解法二】快慢指针

我们使用第二种方法,快慢指针的方法,但是这题困难就困难在不是判断有没有环,而是找到环中第一个结点。

这里我们需要画图说明一下了

假设慢指针走了x个结点与快指针相遇,因为快指针速度是慢指针的两倍,所以快指针走过了2x个结点

快慢指针相遇的结点不一定是环的起点,但是由此可知环中有x个结点

image.png

我们假设环的起点,到两个指针相遇点距离 k 个结点。此时我们可以计算出从头到起点的距离为 x - k, 而从相遇点遍历到起点也是 x - k

image.png

此时,我们再用一个指针从头开始遍历,一次一步。慢指针继续一步一步遍历。它们会在走过x-k个结点的地方相遇,而相遇的地方就是环的起点。

var detectCycle = function(head) {
    if(head === null) return null
    let slow = head
    let fast = head
    while(fast){
        if(fast.next===null) return null
        slow = slow.next
        fast = fast.next.next
        // 快慢指针相遇
        if(slow === fast){
            let pre = head
            while(slow !== pre){
                pre = pre.next
                slow = slow.next
            }
            return pre
        }
    }
    return null
};

最后,欢迎关注我的专栏,和YK菌做好朋友~