【双指针】
fast指针每次走两步,slow指针每次走一步,如果没有环slow和fast永远不会相遇。
为什么fast和slow指针会在环中相遇?
fast比slow先入环,如果两个指针要相遇,只可能是这样一种情况
可以理解为,fast指针对slow指针的追赶是相对速度1,追赶过程中是一个节点一个节点走的,所以最终一定能相遇。
相遇时:
- slow走过的路程:x + y + n(y+z), n代表slow绕了n圈
- fast走过的路程:x + y + m(y+z),m代表fast饶了m圈
- m > n
因为fast速度是slow两倍:
- 2(x + y + n(y + z)) = x + y + m(y + z)
- x + y = (m - 2n)(y + z)
- x = (m - 2n)(y + z) - y
- y + z就是1圈,假设 o = m-2n,o是一个正整数,那么 x = o(y + z) -y
- 如果o = 1,那么 x = z。
- 如果o > 1,那么 x = (o-1)(y+z) + y + z - y, x = (o-1)(y+z) + z,即x的长度为o-1圈加上z
然而我们并不关心转了几圈,只关心入环点是谁,所以可以只看o=1的情况,此时x=z
- 在相遇点设置一个指针index2,从头结点设置一个指针index1,两个指针同步移动,由于x=z,所以两个指针相遇的点就是入环点!
ps:实际上第一次相遇点肯定是在slow指针的第一圈内,但是这需要数学归纳法的推导,有点难以理解,所以就用了上述推导,设置了slow转的圈数n。
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head, *slow = head;
while (fast!=NULL&&fast->next!= NULL)
{
fast = fast->next->next;//快指针一次走两步
slow = slow->next;//满指针一次走一步
if (slow == fast)
{
ListNode *index2 = fast, *index1 = head;//一个指针从相遇点开始,一个指针从头开始
while (index1 != index2)
{
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;//如果循环结束还没有返回值,说明链表没有环
}