题目描述
方法一(代码简洁 理解较难)
用快慢指针,slow走1步,fast走2步
首先有结论:一个指针从相遇点走,另一个指针从起始点走,一定会在入口点相遇。
证明如下:
设圈的周长为C,在距离入口点X的地方相遇,起始点到入口点为L。
slow走的长度为:L+X
slow在圈中走的路程范围是0<= X <=C-1
为什么是 0<= X <=C-1 ?
因为最好的情况是恰好slow到达入口点fast也到达入口点,所以X==0,最坏的情况是slow在入口点时,fast在slow的前面一个,也就是说它们相距C-1,slow和fast每走一步他们的距离就缩小1,那么要走C-1步就相遇。
fast走的长度是:L + n * C + X,n>=1
fast最少走一圈,此时在入口点相遇,所以 n >=1
因为fast走2步slow走1步,fast走的长度是slow的2倍。得到(L+X)* 2 = L + n * C + X
化简得: L = n * C - X 可以写成 L=(n-1)* C + C - X 更好理解
举两个例子 : 如果n1, L=C-X,meet走C-X就相遇
如果n2, L=2*C-X,meet走一圈后再走C-X就相遇
步骤
1.用快慢指针fast和slow来找到相遇点meet
2.从起始位置和meet位置一起走 相遇就是入口点
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
//1.先找到相遇点
ListNode*slow,*fast,*meet;
slow=fast=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)//找到相遇点了
{
meet=slow;
ListNode*cur=head;
//2.从起始位置开始走,和从meet位置开始走,相遇在入口点
while(meet!=cur)
{
meet=meet->next;
cur=cur->next;
}
return meet;
}
}
return NULL;
}
方法二(代码冗长 思路简单)
用快慢指针找到相遇点后,把相遇点于后面的节点断开,这样就变成了找链表交点的问题,这个问题就不再赘述,不会可以看看
找链表交点
步骤
1.找相遇点(用快慢指针)
2.断开相遇点与相遇点的下一个节点L2
3.数一下两链表的长度
4.让长链表先走差距步
5.然后一起走直到地址相同就找到了
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
//1.找到相遇点
ListNode*fast,*slow,*meet,*L2,*L1=head;
fast=slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
{
//把相遇点于下一个节点(L2)断开
meet=slow;
L2=meet->next;
meet->next=NULL;
//算出L1和L2的长度
int count1=0,count2=0;
while(L1)
{
count1++;
L1=L1->next;
}
ListNode*tmp=L2;
while(tmp)
{
count2++;
tmp=tmp->next;
}
//长步的先走gap
int gap=abs(count1-count2);
L1=head;
if(count1>count2)
{
while(gap--)
{
L1=L1->next;
}
}
else
{
while(gap--)
{
L2=L2->next;
}
}
//一起走
while(L1!=L2)
{
L1=L1->next;
L2=L2->next;
}
return L1;
}
}
return NULL;
}