單連結串列有環的幾個問題
轉自:https://www.cnblogs.com/dancingrain/p/3405197.html
給定一個單連結串列,判斷其中是否有環,已經是一個比較老同時也是比較經典的問題,在網上搜集了一些資料,
然後總結一下大概可以涉及到的問題,以及相應的解法。
首先,關於單連結串列中的環,一般涉及到一下問題:
1.給一個單連結串列,判斷其中是否有環的存在;
2.如果存在環,找出環的入口點;
3.如果存在環,求出環上節點的個數;
4.如果存在環,求出連結串列的長度;
5.如果存在環,求出環上距離任意一個節點最遠的點(對面節點);
6.(擴充套件)如何判斷兩個無環連結串列是否相交;
7.(擴充套件)如果相交,求出第一個相交的節點;
下面,我將針對上面這七個問題一一給出解釋和相應的程式碼。
1.判斷時候有環(連結串列頭指標為head)
對於這個問題我們可以採用“快慢指標”的方法。就是有兩個指標fast和slow,開始的時候兩個指標都指向連結串列頭head,然後在每一步
操作中slow向前走一步即:slow = slow->next,而fast每一步向前兩步即:fast = fast->next->next。
由於fast要比slow移動的快,如果有環,fast一定會先進入環,而slow後進入環。當兩個指標都進入環之後,經過一定步的操作之後
二者一定能夠在環上相遇,並且此時slow還沒有繞環一圈,也就是說一定是在slow走完第一圈之前相遇。證明可以看下圖:
當slow剛進入環時每個指標可能處於上面的情況,接下來slow和fast分別向前走即:
1 2 3 4 5 |
|
也就是說,slow每次向前走一步,fast向前追了兩步,因此每一步操作後fast到slow的距離縮短了1步,這樣繼續下去就會使得
兩者之間的距離逐漸縮小:...、5、4、3、2、1、0 -> 相遇。又因為在同一個環中fast和slow之間的距離不會大於換的長度,因此
到二者相遇的時候slow一定還沒有走完一週(或者正好走完以後,這種情況出現在開始的時候fast和slow都在環的入口處)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
下面看問題2,找出環的入口點:
我結合著下圖講解一下:
從上面的分析知道,當fast和slow相遇時,slow還沒有走完連結串列,假設fast已經在環內迴圈了n(1<= n)圈。假設slow走了s步,則fast走了2s步,又由於
fast走過的步數 = s + n*r(s + 在環上多走的n圈),則有下面的等式:
2*s = s + n * r ; (1)
=> s = n*r (2)
如果假設整個連結串列的長度是L,入口和相遇點的距離是x(如上圖所示),起點到入口點的距離是a(如上圖所示),則有:
a + x = s = n * r; (3) 由(2)推出
a + x = (n - 1) * r + r = (n - 1) * r + (L - a) (4) 由環的長度 = 連結串列總長度 - 起點到入口點的距離求出
a = (n - 1) * r + (L -a -x) (5)
集合式子(5)以及上圖我們可以看出,從連結串列起點head開始到入口點的距離a,與從slow和fast的相遇點(如圖)到入口點的距離相等。
因此我們就可以分別用一個指標(ptr1, prt2),同時從head與slow和fast的相遇點出發,每一次操作走一步,直到ptr1 == ptr2,此時的位置也就是入口點!
到此第二個問題也已經解決。
下面給出示意性的簡單程式碼(沒有測試但是應該沒有問題):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
第3個問題,如果存在環,求環上節點的個數:
對於這個問題,我這裡有兩個思路(肯定還有其它跟好的辦法):
思路1:記錄下相遇節點存入臨時變數tempPtr,然後讓slow(或者fast,都一樣)繼續向前走slow = slow -> next;一直到slow == tempPtr; 此時經過的步數就是環上節點的個數;
思路2: 從相遇點開始slow和fast繼續按照原來的方式向前走slow = slow -> next; fast = fast -> next -> next;直到二者再次專案,此時經過的步數就是環上節點的個數 。
第一種思路很簡單,其實就是一次遍歷連結串列的環,從而統計出點的個數,沒有什麼可以詳細解釋的了。
對於第二種思路,我們可以這樣想,結合上面的分析,fast和slow沒一次操作都會使得兩者之間的距離較少1。我們可以把兩者相遇的時候看做兩者之間的距離正好是整個環的
長度r。因此,當再次相遇的時候所經過的步數正好是環上節點的數目。
由於這兩種思路都比較簡單,程式碼也很容易實現,這裡就不給出了。
問題4是如果存在環,求出連結串列的長度:
到這裡,問題已經簡單的多了,因為我們在問題1、2、3中已經做得足夠的”準備工作“。
我們可以這樣求出整個連結串列的長度:
連結串列長度L = 起點到入口點的距離 + 環的長度r;
已經知道了起點和入口點的位置,那麼兩者之間的距離很好求了吧!環的長度也已經知道了,因此該問題也就迎刃而解了!
問題5是,求出環上距離任意一個節點最遠的點(對面節點)
如下圖所示,點1和4、點2和5、點3和6分別互為”對面節點“ ,也就是換上最遠的點,我們的要求是怎麼求出換上任意一個點的最遠點。
對於換上任意的一個點ptr0, 我們要找到它的”對面點“,可以這樣思考:同樣使用上面的快慢指標的方法,讓slow和fast都指向ptr0,每一步都執行與上面相同的操作(slow每次跳一步,fast每次跳兩步),
當fast = ptr0或者fast = prt0->next的時候slow所指向的節點就是ptr0的”對面節點“。
為什麼是這樣呢?我們可以這樣分析:
如上圖,我們想像一下,把環從ptro處展開,展開後可以是無限長的(如上在6後重復前面的內容)如上圖。
現在問題就簡單了,由於slow移動的距離永遠是fast的一般,因此當fast遍歷玩整個環長度r個節點的時候slow正好遍歷了r/2個節點,
也就是說,此時正好指向距離ptr0最遠的點。
對於問題6(擴充套件)如何判斷兩個無環連結串列是否相交,和7(擴充套件)如果相交,求出第一個相交的節點,其實就是做一個問題的轉化:
假設有連個連結串列listA和listB,如果兩個連結串列都無環,並且有交點,那麼我們可以讓其中一個連結串列(不妨設是listA)的為節點連線到其頭部,這樣在listB中就一定會出現一個環。
因此我們將問題6和7分別轉化成了問題1和2.
看看下圖就會明白了:
到此結束!休息一下!
參考:
http://www.cppblog.com/humanchao/archive/2012/11/12/47357.html
http://blog.csdn.net/liuxialong/article/details/6555850
http://blog.csdn.net/liuxialong/article/details/6555850
歡迎轉載,轉載請註明原地址:http://blog.csdn.net/doufei_ccst/article/details/10578315
相關文章
- 連結串列有環知多少~
- 單連結串列的排序問題排序
- 【連結串列問題】打卡2:刪除單連結串列的第 K個節點
- 單連結串列建立連結串列出現問題
- 資料結構與演算法——連結串列 Linked List(單連結串列、雙向連結串列、單向環形連結串列-Josephu 問題)資料結構演算法
- 演算法題:反轉一個單連結串列&判斷連結串列是否有環演算法
- 【連結串列問題】刪除單連結串列的中間節點
- 單連結串列成環
- java環形連結串列約瑟夫環問題筆記Java筆記
- 【連結串列問題】打卡3:刪除單連結串列的中間節點
- vs2015cordova環境安裝【個人遇到的幾個問題】
- Python 位元組串轉Hex字串(一個久遠的問題點總結)Python字串
- ssh連結問題
- 連結串列專題——面試中常見的連結串列問題面試
- Typora 使用中的幾個問題
- grub常見的幾個問題
- 面試中HashMap連結串列成環的問題你答出了嗎面試HashMap
- 約瑟夫環(Josephus)問題--報數遊戲(連結串列)遊戲
- 靜態連結動態連結的連結順序問題和makefile示例
- 面試官常問的Nginx的幾個問題面試Nginx
- 人臉識別幾個很有用的連結
- 牛客題霸NC132環形連結串列的約瑟夫問題Java題解Java
- 有關 socialiteproviders 存在的幾個問題IDE
- azkaban 安裝中的幾個問題
- Redis學習的幾個小問題Redis
- GTK+2.6 + DirectFB的幾個問題
- 入行 AI 的幾個常見問題AI
- ORACLE通過透明閘道器建dblink連線Postgresql的幾個問題OracleSQL
- Docker奪命連環15問,你能堅持第幾問?Docker
- java_求列舉所有的連續(或單個字元)的子串.Java字元
- 【圖解連結串列類面試題】環形連結串列圖解面試題
- 連結串列反轉問題
- 面試官常問的Nginx的那幾個問題?面試Nginx
- 關於ImageView的幾個常見問題View
- Python import 時要注意的幾個問題PythonImport
- npm module 釋出 遇到的幾個問題NPM
- Swift ABI 穩定後的幾個問題Swift
- 關於解決問題的幾個段位