思路(证明有环):
定义快慢指针fast和slow,fast每次前进两步,slow每次前进一步;
当fast和slow在到达链尾之前相遇的话,就证明有环(类似于在操场上跑步跑的慢的被快的套圈但总会遇到);
思路(找环结点):
fast和slow相遇之后,fast不动,slow回到最初的起点,然后一步一步的等在再次相遇,这时候相遇地点就是环结点
证明如下,是个数学问题。。。
设一环的距离是R,k代表环数
slow走过的距离:AB+BC
fast走过的距离:AB+BC+k*R
因为slow每次一步,fast每次两步,所以距离有两倍关系
2(AB+BC)=AB+BC+k*R
AB+BC=(k-1)*R+BC+CB
AB=(k-1)*R+CB
所以结论就是fast从C->B加k圈停在B的时候,slow正好从A->B到达B
1 #include <iostream> 2 using namespace std; 3 4 typedef struct ListNode* List; 5 struct ListNode { 6 int data; 7 List next; 8 }; 9 10 List judge(List L) { 11 if (L == NULL || L->next == NULL) 12 return NULL; 13 List fast = L;//定义快指针 14 List slow = L;//定义慢指针 15 while (fast->next->next != NULL &&fast->next!=NULL) { 16 fast = fast->next->next; 17 slow = slow->next; 18 //如果指针相遇跳出循环 19 if (fast == slow) 20 break; 21 } 22 //如果到头也没有找到证明没有环 23 if (fast->next == NULL || fast->next->next == NULL) 24 return NULL; 25 26 //此时fast记录相遇点,slow回到头指针 27 slow = L; 28 while (fast != slow) { 29 fast = fast->next; 30 slow = slow->next; 31 } 32 //再次相遇的结点就是环结点 33 return slow; 34 }
思路参考https://segmentfault.com/a/1190000015308120