通俗點聊聊算法 -- 鏈表誤成環

爲什麼鏈表會誤成環

來看一個栗子,最近刷題刷鏈表,經常一不小心就下弄成環然後死循環了。

//ListNode* reverseList(ListNode* head)
//{
//    ListNode* node_temp;
//    ListNode* new_head;
//
//    node_temp = head;
//    //遍歷一個節點,就把它拿下來放到頭去
//    while (head->next != NULL)
//    {
//        //先考慮只又兩個節點的情況 
//        head = head->next;
//        new_head = head;
//        new_head->next = node_temp;
//        node_temp = new_head;
//    }
//    return new_head;
//}

像這樣的,用原有節點進行賦值,就容易成環。
因爲當我把一個原有節點直接掛載到另外一個節點之下時,其實是將其後續節點一併帶過去了。

正確的做法應該是新建一個節點,然後將需要掛載的節點的內容拷貝到新節點裏面,使用新節點去掛載。
如果對鏈表操作不熟,建議先了解一下:回顧通用鏈表 - 親測代碼示例

當然,我的好兄弟以爲他很瞭解鏈表,反正他這兩天一直繞在環裏面出不來。


如何判斷鏈表有環

喔,把你的環,我的環,串一串,串成一個同心圓,出不去,死循環。

其實說簡單也簡單,快慢指針就解決了,快指針兩步走,慢指針一步走,只要兩個指針重合了,那就說明有環,因爲快指針繞回來了。

時間複雜度爲線性,空間複雜度爲常數。

說不簡單也不簡單,因爲你去判斷一個鏈表是否有環,那頂多是在測試環節,放在發佈環節未免顯得太刻意,連代碼是否安全都不能保證。

而且,有環的話一般是運行不過的,不用測,運行超時妥妥要考慮一下環的情況,一調試就知道了。


如何判斷環的大小

有了上面的基礎,其實判斷大小是很簡單的。當快慢指針相遇的時候,別停,繼續走,並開始計數,當再次相遇的時候,慢指針走了多少位置,那就是環的長度。


判斷環的入口

這個就比較有意思了,這個不畫圖可能聽不明白。

在這裏插入圖片描述
我這個人,懶了點,來張現成的圖吧。

看啊,在相遇之前呢,慢指針走的距離很好求的:L1 = D+S1;
快指針走的距離:設它在相遇前繞了n圈(n>1),那麼:L2 = D+S1+n(S1+S2);

不過,還有一個等量關係,不要忽略掉,快指針的速度是慢指針的兩倍,所以:L2 = 2L1;
那麼就是:n(S1+S2)-S1 = D;
再轉換一下就是:(n-1)(S1+S2)+S2 = D;

那也就是說,在相遇時候,把一個慢指針放在鏈表頭,開始遍歷,把一個慢指針放在相遇點開始轉圈,當它倆相遇的時候,就是入環點了。


其實吧,用腦子想一開始很難想出來,用手想就快多了。

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