Lintcode 103. 带环链表 II
题目描述:给定一个链表,如果链表中存在环,则返回到链表中环的起始节点,如果没有环,返回null。
说明:
这道题是上一道 102. 带环链表 的变形,这里除了判断是否有环之外,当有环时还需要返回环的入口地点。下面程序是基于一个结论进行实现的:最开始快指针每次走2步,慢指针每次走1步,当它俩相遇时证明有环,此时将慢指针重新拉回到链表最初的head位置,然后快慢指针同时往前走,每次走1步,这次相遇的位置就会是环的入口地点。(这个结论是可以证明的)
解题思路:
- 使用双指针判断链表中是否有环,slow慢指针每次走一步,fast快指针每次走两步,若链表中有环,则两指针必定相遇。
- 假设环的长度为l,环上入口距离链表头距离为a,两指针第一次相遇处距离环入口为b,则另一段环的长度为c=l-b,由于fast走过的距离是slow的两倍,则有a+l+b=2*(a+b),又有l=b+c,可得a=c,故当判断有环时(slow==fast)时,从头移动slow,同时移动fast,两指针相遇处即为环的入口。
/**
* Definition of singly-linked-list:
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: The first node of linked list.
* @return: The node where the cycle begins. if there is no cycle, return null
*/
ListNode * detectCycle(ListNode * head) {
ListNode *slow, *fast;
if (nullptr == head) {
return nullptr;
}
slow= head;
fast = head;
while (nullptr != fast->next && nullptr != fast->next->next) {
slow= slow->next;
fast = fast->next->next;
if (slow== fast) {
//快慢指针相遇
slow= head;//慢指针从头开始走
while (slow!= fast) {
//快慢指针同时移动每次走一步
fast = fast->next;
slow= slow->next;
}
return slow;//两指针相遇位置即为环的入口
}
}
return nullptr;
}
};