LeetCode 142 环形链表 II

链接:https://leetcode-cn.com/problems/linked-list-cycle-ii

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

 

示例 :

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

 

 

这道题的解法十分巧妙,只能膜拜。。用到了快慢指针,让快慢指针同时走,但是快指针一次走两步,慢指针一次走一步。可以想象,当慢指针走到出现环的交点时,快指针已经走到环中的某个位置了。假设慢指针走了x步到达交点,那么快指针此时已经走了2x步。假设快指针还要走y步再次到达交点,那么当慢指针从交点出发再走y步时,快慢指针相遇,这是因为快指针的速度是慢指针的2倍。当快慢指针相遇时,让慢指针指向头节点,快指针依然在相遇的位置,这时让快慢指针都是一次走一步,那么当快慢指针再次相遇的时候,就是所求的出现环的交点。这是因为,慢指针从头节点走x步到达交点,和之前一样。而快指针从相遇位置也是再走x步到达交点。

这道题画个图就很清楚,环的位置其实是求快慢指针再次相遇时所在位置。

如果不存在环,那么快慢指针不会走到环中去,由于快指针走的快,所以它会一直走到空。当出现空的时候,说明不存在环,函数直接返回空就好。

c++代码如下:

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

在写代码的时候,出现了一个bug,看了好久才看出来,错误代码如下:

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

思路是一样的,当快慢指针没有相遇的时候,两个指针以不同的速度向前走,直到相遇时让慢指针回到头节点再开始走,直到快慢节点在交点相遇。区别在于第二个代码先判断了快慢指针是否相遇,而在初始化时快慢指针都指向头节点,所以第6行的判断是不成立的,里面的语句并没有执行。还是要多练习,才能避坑呀。

posted @ 2019-09-23 16:53  wtzhang  阅读(116)  评论(0编辑  收藏  举报