1. 程式人生 > >【連結串列問題】單向連結串列判斷是否有環、求入環節點、求環長、求連結串列長度

【連結串列問題】單向連結串列判斷是否有環、求入環節點、求環長、求連結串列長度

目錄

 

題目:

思路:

程式碼實現

注意點

此題的其他變式


題目

判斷一個單項鍊表是否有環,如果有環,返回入環節點的值,如果無環,返回-1.要求空間複雜度為O(1).

思路

空間複雜度如果沒有要求, 可以用雜湊表來判斷。

在空間複雜度為O(1)的情況下,環狀連結串列相關問題通常用快慢指標來輔助完成

快指標從頭節點開始一次走兩步,慢指標從頭節點開始一次走一步。如果快指標為空或者快指標的next指標指向節點為空,則連結串列無環。

如果快指標和慢指標相遇,則連結串列有環。

在有環的情況下,我們找入環節點。

設環的周長為C,在相遇時,慢指標走的長度為

則快指標一定比慢指標多走(n = 0,1,2...) 的長度,

根據快慢指標的速度關係(快指標一次走兩步,慢指標一次走一步),在相遇的時刻,有

由上面三個式子可得.

快慢指標相遇後,讓快指標指向頭部,慢指標不動。快指標一次走一步,慢指標一次走一步。

當快指標走長度時,慢指標走長度,此時兩指標在入環節點處相遇。

程式碼實現
 

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class ChkLoop {
public:
    int chkLoop(ListNode* head) {
        // write code here
       if(head == NULL || head->next == NULL)
           return -1;
       ListNode *fast = head;
       ListNode *slow = head;
       while(fast!=NULL && fast->next!= NULL){//注意邊界條件
          fast= fast->next->next;
          slow = slow->next;
          if(fast==slow){//有環,第一次相遇
             fast = head;//fast指標到連結串列頭
             while(fast!=slow){
             fast = fast->next;
             slow = slow->next;
             }
             return  fast->val;
          }
       }
       return -1;
       
    }
};

注意點

1、邊界條件的處理,判斷快指標到達連結串列末尾的條件為fast == NULL ||  fast->next == NULL,因為在這兩種情況下fast都不能繼續往下走了。

2、函式開頭對明顯的空連結串列和只有一個節點的連結串列進行處理。

此題的其他變式

1、求單鏈表的環長

快慢指標第一次相遇後,繼續快指標一次兩步,慢指標一次一步,這樣就變成了追及問題。從第一次相遇時刻到到第二次相遇時刻,快指標走的長度比慢指標多一圈。

2、判斷有環單鏈表的長度

環長+頭結點到入環節點的長度(lenA)