LeetCode 142. 环形链表 II

236 阅读2分钟

目录:算法日记

原题链接:142. 环形链表 II - 力扣(LeetCode) (leetcode-cn.com)

题目描述

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

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

不允许修改链表。

数据范围

  • 链表中节点的数目范围在范围[0,104][0, 10^4]
  • 105 <=Node.val<=105-10^5 <= Node.val <= 10^5
  • pos的值为1-1或者链表中的一个有效索引
  • 使用 O(1) 空间复杂度解决此题

题目示例

circularlinkedlist.png

输入: head = [3,2,0,-4], pos = 1
输出: 返回索引为 1 的链表节点
解释: 链表中有一个环,其尾部连接到第二个节点。

算法思路

设置两个指针,蓝色为快指针,黄色为慢指针。快指针小蓝每次走两步,慢指针小黄每次走一步。若不存在环,则快指针小蓝一定可以走到null。若存在环,由于环上每个结点出边唯一,因此快指针小蓝一定可以和慢指针小黄在环上某点相遇,相遇点记为汇合点,进入环的入口记为入口QQ截图20220101092846.png

设起点到入口的距离为xx,则当慢指针小黄走到入口处时,快指针小蓝已走了2x2x,记此时快指针小蓝所在位置为标记点,则入口到标记点的距离为xx。为了方便表述,设入口到汇合点的距离为yy,则慢指针小黄从入口处开始到汇合点走了yy步,快指针小蓝从标记点到汇合点走了2y2y步,因此,标记点到入口的距离也为yy

综上所述,入口到标记点的距离为xx,标记点到入口的距离为yy,入口到会合点的距离也为yy,因此,汇合点到入口的距离即为xx。到这里就可以得出,从起点到入口的距离,与从汇合点到入口的距离是相等的QQ截图20220101105046.png

根据上述证明,首先通过快慢指针找到汇合点,然后两个指针分别从起点与汇合点同速出发,相遇点即为入口。注意特判不存在环的情况。

AC代码

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

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    if(head == null || head.next == null) return null;
    let slow = head;
    let fast = head;
    while(fast != null) { 
        slow = slow.next;
        fast = fast.next;
        if(fast == null) return null;
        fast = fast.next;
        if(slow == fast) { //找到汇合点
            slow = head;
            while(slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
    }
    return fast;
};