快慢指针判断单链表中是否存在环,存在返回环的起点的值

时间:2021-03-08 05:23:03

没有头指针的单链表

/*示例结点
struct ListNode{
int val;
struct ListNode *next;
ListNode(int x):val(x),next(NULL){}
};
*/

具体步骤:

1、快指针(p_swift)、慢指针(p_slow)同时指向首元结点。慢指针一次走一步,快指针一次走两步。

2、当快指针(p_swift)指向NULL时,若快慢指针从没有“碰过面”,则该单链表没有环。

3、当快慢指针“碰面”时。将慢指针重新指向首元结点,快慢指针同时一次一步,当它们再次相遇时,指向的结点就是环的起点。


数学推理:

快慢指针判断单链表中是否存在环,存在返回环的起点的值

1、当慢指针走到位置K时(即走到环的起点),快指针走到位置[K+K%(N-K)]。

2、设慢指针再走b步(即快指针再走2b步),快慢指针相遇。设此时相遇的位置为X。

3、得到X=K+b%(N-K)

X=K+K%(N-K)+2b%(N-K)。

联立二式得:(K+b)=i*(N-K); i为整数。

4、所以X=K+b%(N-K),可以化为X=K+[i*(N-K)-K]%(N-K);

5、慢指针重新指向首元结点,需要走K步到达位置K。X再走K步后位置变为K+[i*(N-K)-K]%(N-K)+K%(N-K)=K。

此时快慢指针正好在环的起点相遇。

同理,也可知当慢指针指向首元结点后,快慢指针再次相遇的位置就是环的起点。


下面请看代码:(没有环返回-1,有环返回环的起点的值)

int judge(ListNode *head){
ListNode *p_slow,*q_swift;
p_slow=q_swift=head;
if(head->next==NULL)
return -1;
p_slow=p_slow->next;
q_swift=q_swift->next->next;
while(q_swift&&q_swift->next)
{
if(p_slow==q_swift)
{
q_swift=head;
while(q_swift!=p_slow)
{
q_swift=q_swift->next;
p_slow=p_slow->next;
}
return p_slow->val;
}
else
{
p_slow=p_slow->next;
q_swift=q_swift->next->next;
}
}
return -1;
}