給定乙個單鏈表,只給出頭指標h:
1、如何判斷是否存在環?
2、如何知道環的長度?
3、如何找出環的連線點在**?
4、帶環鍊錶的長度是多少?
看了不少帖子,感覺還是要自己總結一下。
1.對於問題1,使用追趕的方法,設定兩個指標slow、fast,從頭指標開始,每次分別前進1步、2步。如存在環,則兩者相遇;如不存在環,fast遇到null退出。
bool i***itsloop(slist *head)
return !(fast == null || fast->next == null);
}
2.記錄碰撞點。保持fast不動,slow繼續移動,再次相遇時,slow移動的步數就是環的長度。
int cyclelength(slist *head)
if (fast == null || fast->next == null)
return null;
slow = slow->next;
while (slow != fast)
return length;
}
還有另外一種方法,就是相遇後,slow和fast繼續走,再次相遇時,slow移動的步數就是環的長度。
證明再次相遇時一定是在第一次相遇的點。
證明:首先易知在slow回到第一次相遇的點時,slow走過了y(環的長度),而fast走過了2y,所以一定相遇。
假如在之前兩點就相遇的話,令slow做過了t步(0t = 2t(mody),因為t=y,與題設矛盾,所以slow和fast的第二次相遇一定是在第一次相遇的地方。
3.遇到碰撞點後,slow回到鍊錶起點並且fast的步長變為1,同時移動.則再次相遇時一定是在連線點。證明如下:
證明:令起點到碰撞點的距離為x,環長為y
(1)求碰撞點繼續移動多長的距離到達連線點
當slow從起點走x步到達碰撞點時,fast已經在環內走了x步了(ny<=x<=(n+1)y,n=0,1,2……),可知fast此時偏離連線點移動了s=x-ny的步長。設經過t次移動後兩個指標相遇,那麼應該有0+t = s + 2t (mod y),顯然t = y-s(取最小正整數解)。下面這張圖可以清晰地表明這種關係,經過t = y-s次移動,p1向前移動了y-s個位置(相當於後退了s),到達p1′處,而p2向前移動了2y-2s個位置(相當於後退了2s),到達p2′處,顯然p1′和p2′是同一點。
所以,碰撞點距離連線點移動了y-s即y-(x-ny)=(n+1)y-x的距離。此時slow重新從起點移動x,則fast移動了y-s+x=(n+1)y-x+x=(n+1)y,也在連線點,所以它們再次相遇。連線點即是它們相遇時所指的點。
slist* findloopport(slist *head)
if (fast == null || fast->next == null)
return null;
slow = head;
while (slow != fast)
return slow;
}
(2)還有一種解法,就是利用問題2中的結果。將slow和fast重新指到起點,然後fast先移動y(環的長度)步,然後slow和fast均以1為步長移動,相遇的點就是連線點.
slist* findloopport(slist *head)
while(slow != fast)
return slow;
}
4.由問題2和問題3的結果就可以知道了。
接下來,程式設計之美3.6就可以給出答案了。
給定兩單鏈表a、b,只給出兩頭指標。請問:
1、如何判斷兩單鏈表(無環)是否相交?
有兩種可取的辦法:
(1)人為構環,將鍊錶a的尾節點指向鍊錶b,再判斷是否構環成功?從鍊錶b的頭指標往下遍歷,如果能夠回到b,則說明相交
(2)判斷兩鍊錶最後乙個節點是否相同,如果相交,則尾節點肯定是同一節點
2、如何判斷兩單鏈表(不知是否有環)相交?
先判斷是否有環,判斷是否有環可以使用追逐辦法,設定兩個指標,乙個走一步,乙個走兩步,如果能相遇則說明存在環
(1)兩個都沒環:回到問題1
(2)乙個有環,乙個沒環:不用判斷了,肯定兩鍊錶不相交
(3)兩個都有環:判斷鍊錶a的碰撞點是否出現在鍊錶b的環中,如果在,則相交。(相交時,環必定是兩鍊錶共有的)
3、如何尋找兩相交鍊錶(不知是否有環)的第乙個相交節點?
同樣,使用追逐辦法先判斷是否存在環,分情況討論
(1)無環:人為構環,將鍊錶a的尾節點指向鍊錶b,則構成乙個帶環的單鏈表。這個問題就轉換成尋找帶環單鏈表的環入口節點。
(2)有環:計算出兩鍊錶的長度la、lb,(環的長度和環到入口點長度之和就是鍊錶長度)
如果la>lb,則鍊錶a指標先走la-lb,然後鍊錶b指標開始走,兩者相遇的點就是相交點
如果lb>la,則鍊錶b指標先走lb-la,然後鍊錶a指標開始走,兩者相遇的點就是相交點
參考:
程式設計之美 鍊錶相交問題
1 判斷兩個鍊錶是否相交 假設兩個鍊錶均不帶環 有四種方法 解法1 直觀的想法 判斷第乙個鍊錶的每個節點是否在第二個鍊錶中,這種方法的時間複雜度為o length h1 length h2 解法2 利用計數的方法 對第乙個鍊錶的節點位址進行hash排序,建立hash表,然後針對第二個鍊錶的每個節點的...
《程式設計之美》兩鍊錶相交及擴充套件詳解
程式設計之美 兩鍊錶相交及擴充套件詳解 給定乙個單鏈表,只給出頭指標h 1 如何判斷是否存在環?2 如何知道環的長度?3 如何找出環的連線點在 4 帶環鍊錶的長度是多少?解法 1 對於問題1,使用追趕的方法,設定兩個指標slow fast,從頭指標開始,每次分別前進1步 2步。如存在環,則兩者相遇 ...
單鏈表相交與環問題
程式設計之美 裡面有一篇是講如何判斷兩鍊錶是否相交,讀後覺得原文太過囉嗦。於是,筆者總結了一下,此類問題可以擴充套件為兩大類,分別是 1 單鏈表與環問題 2 單鏈表相交與環問題 本文 給定兩單鏈表a b,只給出兩頭指標。請問 1 如何判斷兩單鏈表 無環 是否相交?有兩種可取的辦法 1 人為構環,將鍊...