Floyd判圈算法
算法概述
Floyd 判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm)。
是一个可以在有限状态机、迭代函数或者链表上判断是否存在环,求出该环的起点与长度的算法。
思路
设两个指针t
和h
已不同步伐(t
一步h
两步)从起点出发,如果存在环,两个指针必有某时刻相遇。
解决问题
是否存在环
设两个指针t
和h
已不同步伐(t
一步h
两步)从起点出发:
- 如果快指针到达了链表尾部,两者都没相遇,则没有环。
- 如果两个指针相遇,则有环。
环的长度
两个指针相遇,设相遇点为M
,让h
指针留在M
点,t
指针继续前进,每次一步。再次到达M
点时,前进的步数即为环的长度。
环的起点
两个指针相遇,设相遇点为M
,让h
指针留在M
点,t
指针回到原点head
,两个指针同时已每次一步的步伐前进,再次相遇时即为环的起点。
证明
假设
相遇时慢指针走过节点数i
链表起点到环的起点长度为m
环的长度为n
相遇的位置与环的起点距离为k
则有
i = m + a * n + k
因为快指针速度为慢指针2倍
2 * i = m + b * n + k
a
b
分别为慢指针和快指针绕环的圈数。
两式相减得
i = (b - a) * n
即i为环的长度的整数倍
此时将t
指针放回起点head
,两指针均已每次一步的速度前进,当t
指针走到环起点时,前进了m
步,h
指针与head
的距离为i + m
。又因为**i
为环的长度的整数倍**,所以h
指针此时也在环的起点上。
代码实现
//leetcode142:Floyd判圈算法
public ListNode floydCycle(ListNode head) {
if (head == null || head.next == null) return null;
ListNode slow = head.next;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {
if (fast == slow) {
fast = head;
while(fast != slow) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
slow = slow.next;
fast = fast.next.next;
}
return null;
}