單鏈表有關 環 的問題

說起關於單鏈表的環,無非以下幾種常見問題  。
  1求單鏈表是否有環 。 
  2求單鏈表的入環點。   
  3求環的長度。

  對於問題1,記得我第一次接觸的時候,比較暴力,直接定義了個數組存放鏈表所有節點的地址。 遍歷鏈表每讀到下一個節點的時候,都要和已知結點的地址數組比較,看是否相同。這種解法的優點 僅僅是的確很好想,但時間複雜度 空間複雜度都很高。
   因此就要尋找更優的解法,我起初的那個很差且很low的解法可以扔了。
  
  新解法的突破口在哪裏呢。
  想想單鏈表涉及的很多減少複雜度的做法都是定義快慢指針。

  比如打印單鏈表中間節點的值,鏈表長度未知
  大部分人一開始是先遍歷下鏈表,確認長度,然後長度取半,再遍歷到一半的位置。
  其實更優的做法是,定義快慢兩個指針,兩者同時遍歷,快指針一下往後遍歷2個結點,慢指針一下往後遍歷1個結點,等到快指針到鏈表尾巴了,慢指針也走到中間了,打印慢指針所指結點信息就ok了。

  再比如打印單鏈表倒數第k個的值,鏈表長度位置。
  大部分人一開始也是遍歷鏈表確認長度,然後讓 再遍歷到  (長度-k)的位置打印。
  更優做法是,定義快慢指針,快指針先走k個結點,然後慢指針出發,快慢指針同時往後走,快指針到末尾時,慢指針就自然到了倒數k的位置。

 還有類似的問題。。。。
 因此我們能發現單鏈表和快慢指針有着莫大的關聯!!

因此新解法就從這點作爲啓發出發,帶環鏈表的特點是什麼?小笨豬都知道是會從 入環點開始循環。
快慢指針?循環?   是否聯想到追擊相遇問題?

定義快指針每次走2個結點,慢指針走1個結點,如果鏈表沒有環,慢指針一輩子也追不上快指針。
但是有環了就代表快指針到達目的地就會開始打轉,慢指針追上快指針成爲了可能。
因此判斷是否有環函數非常簡單。
快指針遇到NULL就代表有結尾,自然就沒有環。
在快指針沒遇到NULL的情況下,被慢指針追上了,就代表環的存在。

圖示
紅色快指針
藍色慢指針
給了兩個帶環鏈表


   綠色圈起的結點爲相遇點,這個點對於後兩個問題來說非常重要!!!
   有人會擔心一種情況,慢指針進入環區了,然後快指針再次進環,快指針增長大會再次超過慢指針,導致判斷  (慢指針==快指針)被略過。其實並不會! 從快慢指針跳躍長度來想,快指針一下跳2次,慢指針一下跳一次,出現那種情況的前提是,上一步慢指針已經和快指針相等了,然後快指針才能跳過慢指針。但是如果上一步已經相等了,我們還能進入到這一步嗎?顯然不能的。

該求問題2 求單鏈表的入環點。   
還記得剛纔的綠色圈起的相遇點嗎
再定義一個指針從頭節點觸發,慢指針從相遇點出發,兩個指針總會在入環點處碰面。
至於爲什麼這樣做?它的原理是什麼?那就是:記住就好了

  3求環的長度。
  其實和2問題有些像,那就是繼問題1後,快慢指針從相遇點繼續按照快指針2結點,慢指針1結點 走,快慢再次相遇時,它們走過的結點數就是環的長度。


有時還會問道帶環鏈表的總長度, 環長度+頭節點到入環點長度就好,也就是問題2,3的結合。

測試一下。創建一個帶環鏈表,0   1  2  3  4  5  6  7  8  9     入環點選7
   

如預期一樣,789開始無限循環

判斷是否有環


獲取入環點


獲取環長度


結果如下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章