【路飞】leetcode-142.环形链表II

337 阅读2分钟

我正在参与掘金新人创作活动,一起开启写作之路

加油 第 2 练

142. 环形链表 II

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

此题与 环形链表I(判断是否有环相似)可以用相似的方法来解。

方法一:遍历存储

遍历‘head’,每一个遍历到的节点存储到一个容器中,如果后面遍历到已存储过的节点则说明存在环,而这第一个相同节点则为入环的第一个节点

var detectCycle = function(head) {
    if (!head || !head.next) return null;
    var mapper = new Map();
    while(head){
        if(mapper.has(head)){
            return head
        }
        mapper.set(head, head);
        head = head.next
    }
    return null
};

方法二:快慢指针

快慢指针可相遇则说明有环,当两指针相遇时,此时让另一指针从头节点以慢指针的速度出发,那么此指针和慢指针相遇时的节点处则为入环节点。
需要推导一下:

image.png

  • 头节点到入环点距离L0;
  • 入环点到首次相遇点距离L1;
  • 首次相遇点到入环点距离L3;
  • 相遇时慢指针走过的距离:S = L0 + L1;
  • 相遇时快指针走过的距离:F = 2S = S + n(L1 + L2);
  • 可以得知 L0 = (n - 1)(L1 + L2) + L2
  • 头节点到入环点距离 = 从首次入环点绕环(n-1)圈,再回到入环点的距离

image.png image.png

  • 假设快慢指针相遇时slow走了k步,那么fast走了2k步;
  • 由上图可看出fast比slow多走的k步,在环内转了 n 圈;
  • 假设环起点到相遇点距离为m,则头节点到环起点距离为 k - m,即由头节点走 k -m 步就能到达环起点;
  • 如果从相遇点继续前进 k - m 步也恰好到达环起点(从相遇点开始走k步可以转回到相遇点,那走 k - m 步肯定就走到环起点了)
  • 我们把快慢指针中的任一个重新指向head,然后两个指针同速前进,k - m 步后一定会相遇,相遇之处就是环的起点了
var detectCycle = function(head) {
    if (!head || !head.next) return null;
        
    var fast = head,slow = head
    while(fast){
        if(!fast.next){
            return null
        }
        slow = slow.next
        fast = fast.next.next
        if(fast == slow){
            fast = head;
            while (fast != slow) {
                fast = fast.next;
                slow = slow.next;
            }
            // 返回相遇时节点 -- 环起点
            return fast;
        }
    }
    return null
};