链接: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行的判断是不成立的,里面的语句并没有执行。还是要多练习,才能避坑呀。