[路飞]环路检测

103 阅读1分钟

题目描述

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

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

分析

输入:链表头节点 head
输出:链表入口节点 / null

解题思路

这道题的关键在于两点:有没有环;若有,环的入口怎么找。

对于第一点,我们用快慢指针轻松证明~

对于第二点,我们做一些证明。

我们看官方的这张图。

image.png

对于 fast 走过的距离:a + n(b + c) + b = a + (n + 1)b + nc 对于 slow:a + b

因为存在一倍差距,所以可得: a + (n + 1)b + nc = 2a + 2b => a = (n - 1)(b + c) + c

所以如果不考虑绕多少圈,a = c,所以让 slow 节点 head 走到环入口和让 fast 从相遇的位置走到环入口的距离是一样的,我们可以据此得出,二者相遇时,都处在环入口节点,我们返回它即可

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function (head) {
  let fast = head
  let slow = head

  while (fast && fast.next) {
    fast = fast.next.next
    slow = slow.next

    if (fast === slow) {
      slow = head

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

      return slow
    }
  }

  return null
}

复杂度

时间:O(N),需要遍历链表
空间:O(1),需要存储几个指针