题目描述
给定一个链表,判断是否存在环。
进一步:能否只使用额外 O(1) 的空间?
算法
(链表,指针扫描) O(n)
用两个指针从头开始扫描,第一个指针每次走一步,第二个指针每次走两步。如果走到 null,说明不存在环;否则如果两个指针相遇,则说明存在环。
为什么呢?
假设链表存在环,则当第一个指针走到环入口时,第二个指针已经走到环上的某个位置,距离环入口还差 x步。
由于第二个指针每次比第一个指针多走一步,所以第一个指针再走 x步,两个指针就相遇了。
时间复杂度分析:第一个指针在环上走不到一圈,所以第一个指针走的总步数小于链表总长度。而第二个指针走的路程是第一个指针的两倍,所以总时间复杂度是 O(n)。
为什么low指针在环上走不到一圈?假想两个人同时同地在操场上起跑,他们之间速度差的一倍,跑得慢的跑完一圈,跑得快的一定刚好跑完两圈,那么在这个过程中,他们一定相遇过。而算法需要在相遇的时候返回true,所以跑得慢的一定跑不完全程。如果他们起跑的时间相同但是位置不同,也是一样的,跑得慢的跑完一圈,跑的快的在跑完两圈的过程中,也一定要超越跑得慢的一次才能回到自己的起点。
C++ 代码
solution中的标答:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(!head||!head->next) return false;
ListNode* fast = head->next;
ListNode* low = head;
while(fast!=low){
if(!fast||!fast->next) return false;
fast = fast->next->next;
low = low->next;
}
return true;
}
};
我开始的while循环是这样写的:
while(fast!=low&&fast&&fast->next){
fast = fast->next->next;
low = low->next;
}
if(fast&&fast->next) return true;
else return false;
这样写比较慢,参见下面的执行时间:
作者:yxc
链接:https://www.acwing.com/solution/LeetCode/content/242/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。