Linked List Cycle

Problem I:

Given a linked list, determine if it has a cycle in it.

Problem II:

Given a linked list, return the node where the cycle begins, if there is no cycle, return null.

Follow up:

Can you solve it without using extra space?

分析:

第一个问题要求检测链表中是否有环路。解决思路很直观,用快慢指针,一个一次一步,另一个一次两步,如果有环路,两个指针必然相遇。

第二问是在第一问的基础上进一步讨论环路的起点在哪里,间接的问题也是在问两个指针相遇在哪里。先看例子,比较直观。下图中的链表一共有5个节点组成,其中3个构成环路。慢指针从头节点开始,需要两步走到环路的起点(3),快指针一次走两步,两次到(5)。两个指针的相遇是在(4)上,慢指针一共走了3步,快指针一共走了6步。接下来做点简单的理论分析。有以下几个结论:

(1) 相遇的地点一定在环路上;

(2) 相遇时,慢指针一定在环路上走了小于等于一圈;

(3) 假设慢指针需要k步走到环路的起点,相遇时慢指针走了m步,那么快指针走了2m步,且相遇点是在偏离环路起点m-k的位置(0≤m-k<n,其中n为环路的节点数),并且m = λn。

结论(1)是显然的。两个同时出发的指针,一个速度是另外一个的两倍,如果一直走在直线上,永远都不可能相遇。有环路时,一旦进入环路就不可能出来,所以相遇的地点必然在环路上。

结论(2)也比较显然,两个指针如果绕着一个环开始走,慢指针走了一圈时,快指针一定走了两圈,两者相遇的地点恰好是起始的位置。而如果环路的前面有一段直线,当慢指针走到环路的起点时,快指针已经绕着环走了一些时候,快指针所处的位置,如果在环路起点,则与前面讨论的情况一样,它们会在环路起点相遇;如果在环路上别的位置,就已经领先了慢指针一些距离,那么慢指针一定走不满一圈就被追上了。

有了结论(2),相遇时,快指针走2m步也就是显然的。

假设相遇点偏离了环路起点x步,对于慢指针在环路外走了k步,环路上走了x步,一共走了m步,所以

k + x = m

对于快指针,在环路外走了k步,环路上绕着环至少绕了一圈,设走了λn步(λ≥1),一共走了2m步,所以

k + (x + λn) = 2m

两式相减得到m = λn。所以相遇点x = m - k,也即x = λn - k,这个关系提示我们,如果从相遇点开始走,那么k步之后可以走回起始点,所以可以让一个指针从其实位置走,另外一个指针从相遇点开始走,k步之后它们会在环路的起点相遇。

对于图中的例子,k = 2,x = 1,m = 3,n = 3,λ = 1。k越大,环越小λ也会越大,相遇也就越慢,不过不管k有多大,快指针也不会访问整个链表两遍,所以不用担心算法很慢,还是线性的时间复杂度。题目的代码比分析要简洁的多了。

 1 class Solution {
 2 public:
 3     ListNode *detectCycle(ListNode *head) {
 4         if(head == NULL)
 5             return NULL;
 6         
 7         ListNode *slow, *fast;
 8         slow = fast = head;
 9         while(fast->next != NULL && fast->next->next != NULL) {
10             slow = slow->next;
11             fast = fast->next->next;
12             if(slow == fast) { // meet
13                 slow = head;
14                 while(slow != fast) {
15                     slow = slow->next;
16                     fast = fast->next;
17                 }
18                 return slow;
19             }
20         }
21         
22         return NULL;
23     }
24 };

 

posted @ 2014-04-29 20:17  夏目家的猫咪老师  阅读(336)  评论(0编辑  收藏  举报