判断单链表中是否有环,找到环的入口节点:在MeetingNode方法中,当快慢指针(slow、fast)相遇时,slow指针肯定没有遍历完链表,而fast指针已经在环内循环了n(n>=1)圈。假设slow指针走了s步,则fast指针走了2s步。同时,fast指针的步数还等于s加上在环上多转的n圈,设环长为r,则满足如下关系表达式:
2s = s + nr;
所以可知:s = nr;
假设链表的头节点到“环的尾节点“的长度为L(注意,L不一定是链表长度),环的入口节点与相遇点的距离为x,链表的头节点到环入口的距离为a,则满足如下关系表达式:
a + x = s = nr;
可得:a + x = (n - 1)r + r = (n - 1)r + (L - a)
进一步得:a = (n - 1)r + (L -a - x)
结论:
1> (L - a -x)为相遇点到环入口节点的距离,即从相遇点开始向前移动(L -a -x)步后,会再次到达环入口节点。
2> 从链表的头节点到环入口节点的距离 = (n - 1) * 环内循环 + 相遇点到环入口点的距离。
3> 于是从链表头与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
Node* EntryCircle(Node* head)
{
Node *slow = head, *fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
while (head != slow)
{
head = head->next;
slow = slow->next;
}
return slow;
}
}
return NULL;
}
int GetLen(Node *head, Node *end)
{
int len = 0;
while (head != end)
{
head = head->next;
len++;
}
return len;
}
bool InSameCircle(Node* x, Node* y)
{
Node* next=x->next;
while(next!=x)
{
if(next==y) return true;
next=next->next;
}
return false;
}
Node* CrossNode(Node* x, Node* y)
{
if (x == NULL || y == NULL) return NULL;
Node* x1 = EntryCircle(x);
Node* y1 = EntryCircle(y);
if ((x1 != NULL && x1 == y1)
|| (x1 == NULL && y1 == NULL))
{
int len1 = GetLen(x, x1);
int len2 = GetLen(y, y1);
while (len1 > len2)
{
x = x->next;
len1--;
}
while (len2 > len1)
{
y = y->next;
len2--;
}
while (x)
{
if (x == y) return x;
x = x->next;
y = y->next;
}
}
else if(x1 != NULL && y1 != NULL && x1 != y1 && InSameCircle(x1, y1))
{
int len1 = GetLen(x, y1);
int len2 = GetLen(y, x1);
return (len1>len2?x1:y1);
}
return NULL;
}
因篇幅问题不能全部显示,请点此查看更多更全内容