有环的几种情况:
那么怎么样来判断一个单链表是否有环,可以用快慢指针,定义一个slow,再定义一个fast,slow一次走一步,fast一次走两步。当slow进入环中,fast就开始追slow了。只要有环,fast和slow总会相遇。如果没有环。fast就会走到空。
刚开始定义slow和fast在第一个节点位置,slow走一步,fast走两步,直到slow进入环,fast开始追slow,因为fast每次比slow多走一步,所以fast和slow一定会相遇。
也可以假设fast和slow之间的距离是N, fast走两步,slow走一步:
步数 | 距离 |
第一次走后 | fast和slow之间的距离变成了N-1 |
第二次走后 | fast和slow之间的距离变成了N-2 |
第三次走后 | fast和slow之间的距离变成了N-3 |
第四次走后 | fast和slow之间的距离变成了N-4 |
…… | …… |
第N次走后 | fast和slow之间的距离变成了0 |
所以,fast和slow一定会相遇。
完整代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head, *fast = head;
while(fast!= NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
{
return true;
}
}
return false;
}
思考:
如果slow一次走一步,fast一次走三步呢?
假设slow和fast之间的距离是N,slow走一步,fast走三步:
步数 | 当N是偶数 | 当N是奇数 |
第一次走后 | slow和fast之间的距离为N-2 | slow和fast之间的距离为N-2 |
第二次走后 | slow和fast之间的距离为N-4 | slow和fast之间的距离为N-4 |
第三次走后 | slow和fast之间的距离为N-6 | slow和fast之间的距离为N-6 |
…… | …… | …… |
第N次走后 | slow和fast之间的距离为0 | slow和fast之间的距离为-1 |
当N是偶数时,fast和slow也一定会相遇。
当N是奇数时:fast正好反超slow,进入新的追逐,他们之间的距离变成了C-1(C是环的周长);
① 当C-1是偶数时:fast和slow会相遇
② 当C-1是奇数时:fast和slow永远不会相遇。
如果slow一次走一步,fast一次走四步呢?
假设slow和fast之间的距离是N,slow走一步,fast走四步:
步数 | 当N是三的倍数 | 偶数(不是三的倍数) | 奇数(不是三的倍数) |
第一次走后 | slow和fast之间的距离为N-3 | slow和fast之间的距离为N-3 | slow和fast之间的距离为N-3 |
第一次走后 | slow和fast之间的距离为N-6 | slow和fast之间的距离为N-6 | slow和fast之间的距离为N-6 |
第一次走后 | slow和fast之间的距离为N-9 | slow和fast之间的距离为N-9 | slow和fast之间的距离为N-9 |
第一次走后 | slow和fast之间的距离为N-12 | slow和fast之间的距离为N-12 | slow和fast之间的距离为N-12 |
…… | …… | …… | …… |
第一次走后 | slow和fast之间的距离为0 | slow和fast之间的距离为-1 | slow和fast之间的距离为-2 |
当N是三的倍数时,fast和slow会相遇。
当N不是三的倍数时,可能会相遇,也可能永远遇不到。