题目:
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.
思路:
1.首先判断链表中是否有环,参考leetcode#141题。
2.沿用leetcode#141题中判断链表中是否含环的方法。在链表头设置两个标记分别为slow和fast,slow每次往后移动1步,fast每次往后移动2步。若链表中有环,则slow和fast肯定会相遇于环中某个节点。
3.见下图,设链表头结点为A,环的起始结点为B,slow和fast相遇与C点(相遇时slow在环内走过的距离小于等于一个环的周长),设AB间(链表头结点和环起始结点)的距离为s1,BC间(环起始结点和相遇结点)的距离为s2,环的周长为c,相遇时slow走过的距离为k,则fast走过的距离为2k,此时fast绕环次数为n。从问题中,可以提炼出以下几个公式:
①k=s1+s2;
②2k=s1+cn+s2;
联立①②,可得s1=cn-s2,即s1=c(n-1)+c-s2,c-s2即C到B要走的距离(顺时针)。
由上式可知,当fast和slow第一次相遇时,在链表头新建一个entry标记(设置其每一次往后移动距离为1,与slow速度一致),继续让三个标记往后移动,entry和slow一定会相遇于一点,该点即为环的起始结点。
通过代码:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow = head;
ListNode* fast = head;
while(fast!=NULL&&fast->next!=NULL&&fast->next->next!=NULL){
slow = slow->next;
fast = fast->next->next;
if(slow==fast){//slow和fast相遇时在头结点新建entry标记
ListNode* entry = head;
while(entry!=slow){ //entry和slow相遇时跳出循环
entry = entry->next;
slow = slow->next;
}
return entry;
}
}
return NULL;
}
};