問題1:
這是一道演算法題,判斷乙個鍊錶是否有環,相應輸出true或者false。那怎麼考慮這個問題呢?
首先想到的是遍歷鍊錶,有環與無環的區別在於,無環時遍歷會最終停止,而有環則會進入死迴圈,重複遍歷環內節點。因此可以借助於判斷節點是否第二次訪問來判斷有無環。具體做法有以下幾種:
1、雜湊解法。使用乙個hash表,用來儲存遍歷過的節點的位址,若是某個節點的位址在hash表中出現過了,則意味著有環。
2、給每個節點增加乙個額外的引數,比如flag位,每次訪問這個節點就把這個節點的flag位置為1,若是訪問的節點中flag為1,則說明有環。但是這個方法需要修改鍊錶。
上述方法可行,但需要o(n)的空間和o(n)時間,如果要求只用o(1)的空間和o(n)的時間,如何處理?
受啟發於快慢同學繞操場跑步可以第二次相遇,也可以成為快指標和慢指標問題。建立兩個指標,從header開始,向後遍歷,乙個步長為1,乙個步長為2。
(1)如何判斷有環?
如果有兩個頭結點指標,乙個走的快,乙個走的慢,那麼若干步以後,如果有環,兩個指標將相遇;如果無環,快指標先行到達鍊錶尾部null。
(2)如何計算環的長度?
第一次相遇(超一圈)時開始計數,第二次相遇時停止計數,剛好遍歷一圈。
(3)如何查詢環的入口點?
相遇點到入口點的距離=頭指標到入口點的距離+n倍環長,因此,分別從相遇點、頭指標開始走,相遇的那個點就是連線點。
盜個圖,解釋一下:
鍊錶總長度為n,環的長度為m,則迴圈n-m次時,slow指標剛好進環,假設與fast指標相距為x。經過t次迴圈,兩指標相遇,此時
2t=t+m-x,即t=m-x。所以總的時間複雜度為o(n-m+m-x)=o(n-x)=o(n)。
判斷有環和計算環長比較容易理解,下面解釋下如何查詢環的入口點。兩指標第一次相遇時,假設slow走了s步,fast則走了2s步,則2s-s=pm;
假設鍊錶起點到環入口點的長度為a,此時,
slow指標還未走完環一圈
(想一想為什麼),所以a+x=s
綜上,可得,a+x=pm=(p-1)m+n-a,
即a=(p-1)m+m-x
所以相遇點到入口點的距離和鍊錶起點到入口點的距離相差環長的整數倍,分別從起點和相遇點以相同速度走,將會在入口點相遇。
參考:
問題2:判斷兩個鍊錶是否相交
可以受啟發於問題1中的解法。
1、兩個無環鏈表是否相交
有以下幾種方法:
(1)雜湊解法
對第乙個鍊錶的節點位址進行hash排序,建立hash表,然後針對第二個鍊錶的每個節點的位址查詢hash表,如果在hash表中出現,那麼說明有共同的節點,時間複雜度為o(l1+l2),但是同時要附加o(l1)的儲存空間。
(2)轉換為問題1。
由於兩個鍊錶都沒有環,我們可以把第二個鍊錶接在第乙個鍊錶後面,如果得到的鍊錶有環,則說明兩個鍊錶相交。
由於兩個無環單向鍊錶,畫出來只可能是2條不相干的鍊錶或乙個」y」字形。我們只需從第二個鍊錶開始遍歷,看是否會回到起點就可以判斷出來,最後,當然可別忘了恢復原來的狀態。
在這種方法下,找到環的入口點即為鍊錶相交的第乙個點。
(3)用指標p1、p2分別指向兩個煉表頭,不斷後移;最後到達各自表尾時,若p1==p2,那麼兩個鍊錶必相交
複雜度為o(l1+l2),比解法3更好。
這時我們記下兩個鍊錶length,再遍歷一次,長鍊表節點先出發前進(lengthmax-lengthmin)步,之後兩個鍊錶同時前進,每次一步,相遇的第一點即為兩個鍊錶相交的第乙個點。
2、兩個鍊錶有環
參考:
鍊錶是否相交,鍊錶是否有環問題
1 乙個單鏈表,判斷是否有環,環的入口節點 分析 兩個指標,慢指標一次走一步,快指標一次走兩步,如果有環肯定會相交 listnode pnode bool i istloop listnode head return false 找出環的入口 環入口到相遇點為x,從開始到環入口點長度為a,環長為r,...
鍊錶有環問題
判斷乙個鍊錶是否有環 解析 如果鍊錶有環,則設定乙個指標,該指標會一直迴圈下去。我們可以設定兩個指標,乙個一次走一步,乙個一次走兩步,如果有環最終兩者會相遇,否則每次走兩步的指標最先走到鍊錶尾部。如下圖 延伸 判斷兩個鍊錶是否相交 給出兩個單向鍊錶的頭指標,比如l1,l2,判斷這倆個鍊錶是否相交。1...
鍊錶之鍊表含環,相交等問題
兩個鍊錶,可能相交,找出相交的節點,給出證明 1.若兩個單鏈表乙個為有環,乙個無環.那麼肯定不能相交.2.若二者都沒有環,問題就轉化為 兩個無環單鏈表是否相交,是否能找到第乙個相交的節點,方法就是 快慢指標 3.若二者都有環,那麼問題變成了兩個有環單鏈表是否相交.第一,先找到二者是否相交.第二,若相...