一个链表中包含环,请找出该链表的环的入口结点。
判断有环:定义两个指针low,fast,low一次走一步,fast一次走两步,有环则两点会重合。
ListNode* circle(ListNode* pHead)
{
if(pHead == NULL)
return NULL;
ListNode* low = pHead;
ListNode* fast = pHead;
while(fast != NULL)
{
if(fast == low)
return low;
low = low->next;
fast = fast->next->next;
}
return NULL;
}
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
找到环切点
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == NULL)
return NULL;
ListNode *slow = pHead, *fast = pHead;
while ( fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if ( slow == fast ) break;
}
if (fast == NULL || fast->next == NULL)
return NULL;
slow = pHead; //一个从头,一个从环中交点,每次走一步,相遇点为环切点
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
定理:
假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系: