leetcode 142. Linked List Cycle II(Floyd判圈算法、双指针)
题目链接
leetcode 142. Linked List Cycle II
题目大意
给定一个链表,判断链表内部是否含有环。输出环的起始位置。不能有额外的存储空间。
思路
利用双指针,慢指针每次前进一个节点,快指针每次前进两个节点;
设从出发点到环的起点的距离为
L
1
L_1
L1,两个指针第一次相遇的位置距离环的起点为
L
2
L_2
L2,环的长度为
N
N
N,
那么从出发点到相遇时,慢指针走过的节点数为:
L
1
+
L
2
+
N
∗
a
L_1+L_2+N*a
L1+L2+N∗a
快指针走过的节点数为:
L
1
+
L
2
+
N
∗
b
L_1+L_2+N*b
L1+L2+N∗b
由于快指针速度是慢指针的两倍,那么有:
2
∗
(
L
1
+
L
2
+
N
∗
b
)
=
L
1
+
L
2
+
N
∗
a
2*(L_1+L_2+N*b)=L_1+L_2+N*a
2∗(L1+L2+N∗b)=L1+L2+N∗a
化简得:
L
1
+
L
2
=
(
a
−
2
b
)
∗
N
L_1+L_2=(a-2b)*N
L1+L2=(a−2b)∗N,即从出发点到两者相遇点的距离=环的长度的整数倍
此时需要求取 L 1 L_1 L1的长度,由 L 1 + L 2 = ( a − 2 b ) ∗ N L_1+L_2=(a-2b)*N L1+L2=(a−2b)∗N==> L 1 = N − L 2 L_1=N-L_2 L1=N−L2,故只需维护一个指针从出发点开始,一个指针从相遇点开始,两者的下一次相遇就是环的起始位置。
Floyd判圈算法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//返回链表环开始的节点
//不利用多余的内存空间
//双指针,floyd判圈算法
ListNode *detectCycle(ListNode *head) {
ListNode *l=head,*r=head;
if(head==NULL || head->next==NULL) {
return NULL;
}
while(r && r ->next){
l=l->next;
r=r->next->next;
if(l==r){
ListNode *tmp=head;
while(tmp!=l){
tmp=tmp->next;
l=l->next;
}
return tmp;
}
}
return NULL;
}
};