可以考虑在一个链表上,Floyd环检测可以检测出是否有环,并且能找到环的入口
其实本质上就是利用快慢指针
快指针每次移动2下,而慢指针每次移动1下
显然,如果没有环,快指针将会直接到达链表的末尾
如果有环,
设起点到环的距离为
T
T
T,环的长度为
c
c
c
设当慢指针第一次到达环入口的时候,快指针到环的入口的距离为
r
r
r
慢指针移动距离
T
T
T
快指针移动距离
T
+
r
+
k
c
(
k
∈
N
)
T+r+kc\left(k\in\mathbb{N}\right)
T+r+kc(k∈N)
因为快指针移动速度是慢指针2倍,所以距离也是两倍,所以
2
T
=
T
+
r
+
k
c
⇒
T
=
r
+
k
c
2T=T+r+kc\Rightarrow T=r+kc
2T=T+r+kc⇒T=r+kc
接着考虑什么时候他们相遇
快指针在慢指针的前面
r
r
r的距离,也可以看成是慢指针在快指针前
c
−
r
c-r
c−r的距离
因为他们的速度差为
1
1
1,所以再经过
c
−
r
c-r
c−r次移动,快指针将会追上慢指针
这就是检测是否有环了
那怎么检测环入口呢
注意到
T
=
r
+
k
c
T=r+kc
T=r+kc,而快指针现在到环的出口的距离为r
我们让慢指针回到起点
让快指针和慢指针以1的速度移动
当慢指针到达换的入口的时候,移动的距离为
T
T
T
那么快指针移动的距离也是
T
T
T
而
T
=
r
+
k
c
T=r+kc
T=r+kc,即快指针到达了环的入口
也就是说他们相遇的时候,就是环的入口了
例题
Leetcode141
这个就是环检测了
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==nullptr)return false;
ListNode* p=head,*q=head;
while(p->next && p->next->next){
p=p->next->next;
q=q->next;
if(p==q)return true;
}
return false;
}
};
Leetcode142
这个就是环入口检测了
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head==nullptr){
return nullptr;
}
ListNode* fast=head,*slow=head;
while(fast->next&&fast->next->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
break;
}
}
if(fast->next==nullptr||fast->next->next==nullptr){
return nullptr;
}
slow=head;
while(fast!=slow){
fast=fast->next;
slow=slow->next;
}
return fast;
}
};