Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?
这个题目是在一版的基础上,需要返回循环的起点,我自己是不会做的!参考了别人博客,并自己进行了深入的思考,下面娓娓道来。
首先看图,画的不好见谅。还是使用快慢指针的方法,分别为1,2表示。一个每次走一步,一个每次走2步。在图中这个情况下,慢指针需要走3步才能到达循环开始的节点处,而此时的快指针已经进入了循环。由图中可知,此时1指针才刚到循环的开始处,而2指针已经在循环里走了3步。那该如何得到走多少步之后2个指针才能重合呢。假设需要走x步才能重合,现在1指针在循环中的位置为0,2指针为3。那么0+x 和 2x+3 的值对循环圈的长度,即4,取模之后的结果应该是相同的,表示处在环上的某一个相同位置上。考虑到2指针由于步长是2,很有可能在走过x步之后已经绕了一圈,所以这里我做个假设,做了个等式,x = 2x + 3 - 4, 即x = 4 - 3。就是使用环长减去头节点到环开始处的长度,这个步数的计算方法是我在别人博客里看来的,但是人家写的时候并没有做太多解释,前文中的那些推论都是我自己画图琢磨时的一些感悟,若有错误,轻喷。由此可得到需要走多少步,2个指针会重合,之后你就会神奇的发现,由于环长是4,x为1,慢指针和快指针走了一次之后就重合了,此时,慢指针如果需要再走到,环头,还需要4-x步,即3步,但是各位有没发现x就是由4-3,环长减去头节点到环头的长度得来的,所以忽然发现,重合点的位置到环头的距离与头节点到环头的距离是一样的,由此就可以轻松的找到环头节点的指针了。之后你也会发现在环中重合一次之后,下一次重合是5步之后,即x加上环长4。我觉得这题还真需要好好画图推演,找到相应的定理才好理解,,,但是其中的缘由是什么我也并步太清楚,只是自己做出了一些推断。
可能有 比较细心的同学会说,如果是环的长度比头节点到环头的距离小呢,想得到x步就是负数了吗,,我也考虑到这个问题了,只需将环长翻倍即可,乘2不够就乘3,然后再减,即可得到需要多少步可以重合。具体的图就不画了,画的太丑了。
我也不是什么数学高手,,只是个破代码屌丝,,说实话这个题目我是真不会做,全是去百度查的,然后看别人的博客,听人家说的那些定理,然后步理解,自己画图然后慢慢走几遍,才算有点非常浅薄甚至可能不正确的理解,仅供大家参考,说错的地方也勿喷,,,,欢迎交流,下面上代码,还是比较容易理解的,主要是了解这个快慢指针与环的原理就行了。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (head == NULL) {
return NULL;
}
ListNode * slow = head;
ListNode * fast = head;
while (slow->next && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (!fast) {
break;
}
if (slow == fast) {
fast = head;
while (fast != slow) {
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return NULL;
}
};