题目
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
图片来自leetcode-cn.com
思路
这里只介绍快慢指针的思路,直观的从距离的角度分析,还有一种思路用另一种数据结构存储比较的就不说了。
- 首先我们要明白一点,如果链表存在环,那么快慢指针一定会在环里的某一点相遇,因为快指针肯定会追上慢指针。
上图
我们假设两个指针相遇在 C
点。
此时可以计算两个指针走过的距离。
假设从发出点
到 环形入口
的距离 为 X
,相遇点
到 环形入口
的距离为 Y
,环的周长
为 r
S
l
=
X
+
k
1
r
+
Y
S_ l=X+k_1r+Y
Sl=X+k1r+Y
S
f
=
X
+
k
2
r
+
Y
=
2
S
l
S_ f=X+k_2r+Y=2S_l
Sf=X+k2r+Y=2Sl
相减可得
S
l
=
X
+
k
1
r
+
Y
=
(
k
1
−
k
2
)
r
S_ l=X+k_1r+Y=(k_1-k_2)r
Sl=X+k1r+Y=(k1−k2)r
那我们就可以得到
从发出点
到 环形入口
的距离 X
的值为:
X
=
(
k
2
−
2
k
1
)
r
−
Y
=
k
3
r
−
Y
X =(k_2-2k_1)r-Y=k_3r-Y
X=(k2−2k1)r−Y=k3r−Y
也就是说快慢指针相遇后,我们让慢指针回到 出发点
,此时令快慢指针速度相同
,当慢指针到 环形入口
时,走的距离 是让快指针走
k
3
k_3
k3圈,再少Y
, 忽略掉
k
3
k_3
k3圈,就是回退Y
步,就是正好为 环形入口
。
代码
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) return null;
ListNode fast = head, slow = head;
do {
if (fast.next == null || fast.next.next == null) return null;
slow = slow.next;
fast = fast.next.next;
}while (slow != fast);
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
}