尋找有環單鏈表的入口節點
阿新 • • 發佈:2019-02-01
問題陳述:一個可能存在環的單鏈表,尋找環的入口節點。
連結串列節點描述:
struct ListNode {
int num;
ListNode * next;
};
這一問題有許多解法,這裡說明三種『記數法』『斷鏈法』『差速法』,各有優劣。前兩種方法相對容易理解,第三種方法則相對優雅一些,建議直接看第三種方法。同時,這一問的演算法也可以用來判斷連結串列是否存在環。
一、記數法
這是最容易想到的方法,基於這樣一個既定的事實:點連結串列的環一定是單環(最簡單的那種),而且連結串列的尾節點一定指向環的入口節點。這樣的環只有三種形式:數字0型,數字6型,數字9型。 這樣看來,問題似乎就變成了尋找單鏈表的尾節點。然而可惜的是,由於環的尋在,尾節點已是不可尋了。ListNode* EntryNodeOfLoop(ListNode* pHead) {
if(!pHead)
return null; map<ListNode*,int> flag; while(pHead) { if(++flag[pHead] == 2) return pHead; pHead=pHead->next; } return null; }
二、斷鏈法
斷鏈法的依據也是連結串列中只有環的入口節點由兩個指標指向它。這樣,我們就可以遍歷連結串列,依次刪除節點之間的連線,直到遇到空指標,最後這個節點一定就是環的入口節點。
很明顯,這樣的做法會破環連結串列本身的結構,屬於傷敵一萬,自損八千的做法。
參考程式碼:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
if(pHead == null|| pHead.next == null)
這個方法還有一個致命的缺點,就是當連結串列中沒有環的時候,它返回的是尾節點,但此時的尾節點並不是環的入口。return null; ListNode* fast=pHead->next; ListNode* slow=pHead; while(fast != null) { slow->next = null; slow = fast; fast = fast->next; } return slow; }
三、差速法
所謂的差速就是指兩個移動速度不一樣的快慢指標。在講述這個演算法之前,首先需要一點點的數學證明。
ListNode* EntryNodeOfLoop(ListNode* pHead) {
if(pHead == null|| pHead.next == null|| pHead.next.next == null)
return null;
ListNode* fast = pHead->next->next;
ListNode* slow = pHead->next;
while(fast! = slow) {
if(fast->next != null && fast->next->next != null) {
fast = fast->next->next;
slow = slow->next;
}
else{
return null;
}
}
fast = pHead;
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return slow;
}
結束。