142. Linked List Cycle II
没看题解时,我想到的是配合141题的查找是否有环,如果有,再遍历每个元素。依据是:如果有一个环,将快慢指针设置在入环处,那么快慢指针下一个(或者N次)相遇必定也在入环处。于是开始写出来的是时间复杂度比较差的算法。
bool hasCycle(struct ListNode *head) {
if(head == NULL)
return false;
struct ListNode *slow = head, *fast = head;
int ret = 0;
while(fast->next != NULL && fast->next->next != NULL ) {
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
ret = 1;
break;
}
}
if(ret == 1)
return true;
return false;
}
struct ListNode *detectCycle(struct ListNode *head){
if(hasCycle(head) == 0)
return NULL;
struct ListNode *slow = head, *fast = head, *p = head;
while (p){
do{
slow = slow->next;
fast = fast->next->next;
}while(slow != fast);
if(slow == p){
return p;
}
p = p->next;
slow = p;
fast = p;
}
return NULL;
}*/
看了题解后发现可以用数学知识来得到入口与环之间的关系,然后先是自己倒腾了一些,发现推出来的带一些余数并且不能抵消,再去看看题解,看到一句话,两指针在环内相遇时,慢指针环内走的距离必然不会超过一个环(当入环口恰好在头指针时,下一次相遇也在头指针,这种情况也可以算在上面),这个结论假设一下就出来了:如果慢指针走了一个环的距离,此时快指针就走了两个环的距离,那么就会相遇,如果慢指针走了超过了一个环的距离,快指针就和慢指针已经相遇过一次了,如果入环口不在头指针,那么相遇的点肯定在入环口与链表“最后一个结点”之间
struct ListNode *detectCycle(struct ListNode *head) {
if(head == NULL)
return NULL;
struct ListNode *slow = head, *fast = head;
int ret = 0;
while(fast->next != NULL && fast->next->next != NULL ) {
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
ret = 1;
break;
}
}
if(ret == 1){
struct ListNode *third = head;
while(slow != third){
slow = slow->next;
third = third->next;
}
return slow;
}
return NULL;
}