帶環連結串列得幾個問題
阿新 • • 發佈:2019-02-11
1、判斷一個連結串列是否有環,如果有環,則返回入環的第一個節點,否則返回null
如果一個連結串列有環,遍歷一個連結串列便永遠不會到達null,否則必定會到達null。設定兩個指標,剛開始都指向頭節點,遍歷時,一個指標每次前進一步,我們稱之為慢指標,另一個每次前進兩步,稱之為快指標,這樣,如果連結串列沒有環,快指標必然會到達null,如果有環,兩個指標必然會相交於一點。
下面再來看看如何找到入環的第一個節點,假設從頭節點到入環第一個節點的長度為m,兩個指標第一次相遇時的節點距離環入口點的長度為t,環的長度為n,那麼此時慢指標走的長度為m+t,快指標走的長度為m+t+kn(k=0,1,2...),kn項表示快指標有可能在環內走了幾圈後再與慢指標相遇,這時滿足
m+t+kn = 2(m+t)
簡化得到
m = (k-1)n + n - t
其中n-t項正表示了慢指標走完當前環還需要走的長度,從這裡就可以看出此時如果將快指標放回頭節點,然後讓它每次只走一步,那麼這兩個指標必然會相交,並且相交的交點就是入環點。
ListNode *detectCycle(ListNode *head) { ListNode *fast = head; ListNode *slow = head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } if (fast == NULL || fast->next == NULL) return NULL; slow = head; while (slow != fast) { slow = slow->next; fast = fast->next; } return slow; }
2、判斷兩個連結串列是否相交,相交則返回第一個交點
如果兩個連結串列相交,則交點後面部分兩個連結串列是相同的,當然長度也就相同,關鍵在於兩個連結串列不相交的部分,所以可以先求出兩個連結串列的長度len1和len2,如果len1大於len2,則連結串列1先開始往前走,直到從當前節點開始兩個連結串列的長度相同,然後再同時前進,直到兩個節點相同,就是第一個交點。
int getListLength(ListNode *list) { ListNode *p = list; int len = 0; while (p) { len++; p = p->next; } return len; } /** * @param headA: the first list * @param headB: the second list * @return: a ListNode */ ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { if (!headA || !headB) { return nullptr; } int lenA = getListLength(headA); int lenB = getListLength(headB); while (lenA > lenB) { headA = headA->next; lenA--; } while (lenA < lenB) { headB = headB->next; lenB--; } while (headA != headB) { headA = headA->next; headB = headB->next; } return headA; }
3、如何判斷兩個有環連結串列是否相交,相交則返回第一個相交點
這個問題可以首先利用問題1分別獲得兩個連結串列的環入口點loop1和loop2,此時如果loop1和loop2相等,則表明兩個連結串列在入環前就已經相交,這個時候可以利用問題2的方法獲得相交點,只是把loop1當作尾節點即可。 如果loop1和loop2不相等呢,這個時候有兩種情況,要麼兩個連結串列不相交,要麼兩個連結串列在環內相交。這個時候可以從loop1出發走一圈,如果在回到loop1的時候一直沒有遇到loop2,那麼表明兩個連結串列不相交,否則就相交,此時返回loop1或者loop2都可以。ListNode* bothLoop(ListNode* head1, ListNode* loop1, ListNode* head2, ListNode* loop2)
{
ListNode* cur1 = nullptr;
ListNode* cur2 = nullptr;
if (loop1 == loop2)
{
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1)
{
n++;
cur1 = cur1->next;
}
while (cur2 != loop2)
{
n--;
cur2 = cur2->next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = abs(n);
while (n != 0)
{
n--;
cur1 = cur1->next;
}
while (cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
else
{
cur1 = loop1->next;
while (cur1 != loop1)
{
if (cur1 == loop2)
{
return loop1;
}
cur1 = cur1->next;
}
return nullptr;
}
}