【LeetCode 142】环形链表 II:寻找环的入口
一、题目描述
给定一个链表的头节点 head
,如果链表中存在环,返回环的 入口节点;否则返回 null
。
环的入口节点:指链表中开始进入环的第一个节点。
链表中节点数目范围
[0, 10^4]
,节点值在[-10^5, 10^5]
。
二、思路分析
这道题是 141. 环形链表 的升级版。
141 只需要判断是否有环。
142 要求返回环的 入口节点。
核心依然是 快慢指针(Floyd 判圈算法),但需要额外推理。
1. 快慢指针相遇点
慢指针
slow
每次走一步。快指针
fast
每次走两步。若有环,它们一定会在环内某个节点相遇。
2. 数学推导:如何找到入口
设:
链表头到环入口的长度为 x
环入口到相遇点的长度为 y
环剩余部分的长度为 z
那么:
慢指针走过的路程:
x + y
快指针走过的路程:
x + y + n(y+z)
,其中n
表示快指针多绕的圈数。
因为快指针速度是慢指针的两倍:
2(x + y) = x + y + n(y+z)
整理得到
x = (n-1)(y+z) + z
含义是:
从头节点走
x
步就能到入口。从相遇点再走
(n-1)(y+z) + z
步也能到入口。
所以,只要:
一个指针从头开始走。
一个指针从相遇点走。
两者每次都走一步。
它们最终会在环的入口相遇!
三、代码实现
public class Solution {public ListNode detectCycle(ListNode head) {if (head == null || head.next == null) return null;ListNode slow = head, fast = head;// 判断是否有环while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;if (slow == fast) { // 相遇,说明有环ListNode ptr = head;// 两个指针同步前进,必在入口相遇while (ptr != slow) {ptr = ptr.next;slow = slow.next;}return ptr;}}return null; // 无环}
}