如何判斷單鏈表裏面是否有環?

如何判斷單鏈表裏面是否有環?

算法的思想是設定兩個指針p, q,其中p每次向前移動一步,q每次向前移動兩步。那麼如果單鏈表存在環,則p和q相遇;否則q將首先遇到null。
這裏主要理解一個問題,就是爲什麼當單鏈表存在環時,p和q一定會相遇呢?


假定單鏈表的長度爲n,並且該單鏈表是環狀的,那麼第i次迭代時,p指向元素i mod n,q指向2i mod n。因此當i≡2i(mod n)時,p與q相遇。而i≡2i(mod n) => (2i - i) mod n = 0 => i mod n = 0 => 當i=n時,p與q相遇。這裏一個簡單的理解是,p和q同時在操場跑步,其中q的速度是p的兩倍,當他們兩個同時出發時,p跑一圈到達起點,而q此時也剛 好跑完兩圈到達起點。
那麼當p與q起點不同呢?假定第i次迭代時p指向元素i mod n,q指向k+2i mod n,其中0<k<n。那麼i≡(2i+k)(mod n) => (i+k) mod n = 0 => 當i=n-k時,p與q相遇。

解決方案:

推廣:

1. 如果兩個指針的速度不一樣,比如p,q,( 0<p<q)二者滿足什麼樣的關係,可以使得兩者肯定交與一個節點?

    Sp(i) = pi

    Sq(i) = k + qi

   如果兩個要相交於一個節點,則 Sp(i) = Sq(i) =>  (pi) mod n = ( k+ qi ) mod n =>[ (q -p)i + k ]  mod n =0

   =>  (q-p)i + k  = Nn [N 爲自然數]

   =>  i = (Nn -k) /(p-q)

   i取自然數,則當 p,q滿足上面等式 即 存在一個自然數N,可以滿足Nn -k 是 p - q 的倍數時,保證兩者相交。

   特例:如果q 是p 的步長的兩倍,都從同一個起點開始,即 q = 2p , k =0, 那麼等式變爲: Nn=i: 即可以理解爲,當第i次迭代時,i是圈的整數倍時,兩者都可以交,交點就是爲起點。

2.如何判斷單鏈表的環的長度?

   這個比較簡單,知道q 已經進入到環裏,保存該位置。然後由該位置遍歷,當再次碰到該q 位置即可,所迭代的次數就是環的長度。

3. 如何找到鏈表中第一個在環裏的節點?

   假設鏈表長度是L,前半部分長度爲k-1,那麼第一個再環裏的節點是k,環的長度是 n, 那麼當q=2p時, 什麼時候第一次相交呢?當q指針走到第k個節點時,q指針已經在環的第 k mod n 的位置。即p和q 相差k個元素,從不同的起點開始,則相交的位置爲 n-k, 則有了下面的圖:

從圖上可以明顯看到,當p從交點的位置(n-k) ,向前遍歷k個節點就到到達環的第一個幾點,節點k.

算法就很簡單: 一個指針從p和q 中的第一次相交的位置起(n-k),另外一個指針從鏈表頭開始遍歷,其交點就是鏈表中第一個在環裏的交點。

4. 如果判斷兩個單鏈表有交?第一個交點在哪裏?

    這個問題畫出圖,就可以很容易轉化爲前面的題目。

    

    將其中一個鏈表中的尾節點與頭節點聯繫起來,則很容發現問題轉化爲問題3,求有環的鏈表的第一個在環裏的節點。

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