兩個連結串列是否相交
判斷單鏈表中是否有環,找到環的入口節點:在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;
}