环形链表II

36 阅读1分钟

142.环形链表II

力扣题目链接(opens new window)

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

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

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

循环链表

解法

对于这道题,可以设定两个指针,同时从头节点出发,一个一次走一步,一个一次走两步,即一快一慢。如果存在环,那么这两个指针一定会在环中相遇。如下图所示:

截屏2025-09-03 15.46.42.png

慢指针一次走一步,所以慢指针走过的路程为 x + y

快指针在环内走了 n 圈追上慢指针,所以快指针的路程为 x + y + n(y + z),其中 y + z 为一圈的路程。

由于快指针比慢指针快了一倍,可以得到以下公式:

2(x + y) = x + y + n(y + z)

要求的是 x,所以对以上公式进行处理得到:

  1. x + y = n(y + z)
  2. x = n(y + z) - y
  3. x = (n - 1)(y + z) + y + z - y
  4. x = (n - 1)(y + z) + z

其中 n 是大于等于 1 的,所以当 n 等于 1 时,得到 x = z

这时只需慢指针从头出来,快指针从相遇点出发,每次都走一步,那么相遇点就是环入口。

代码

var detectCycle = function(head) {
    if(head === null || head.next === null) {
        return null
    }
    let slow = head
    let fast = head

    do {
         slow = slow.next
        fast = fast.next.next
    } while(slow !== null && fast !== null && fast.next !== null && slow !== fast)

    if(slow === null || fast === null || fast.next === null) {
        return null
    }
    slow = head

    while(slow !== fast) {
        slow = slow.next
        fast = fast.next
    }
    return slow
    
};