142. 環形鏈表 II

中等 哈希表 鏈表 雙指針

思路

假設快指針fastfast每次走兩步,慢指針slowslow每次走一步,如果鏈表當中有環。
最後快指針一定會追上慢指針。 定義以下變數

  • L1L_1:從頭節點\to環起點的距離
  • L2L_2:從環起點\to相遇點的距離。
  • CC:環的長度。 因為快指針的速度是慢指針的兩倍,所以2(L1+L2)=L1+L2+nC2(L_1+L_2)=L_1+L_2+nC,其中nn代表快指針追過了幾圈慢指針。(因為快指針可能直接越過慢指針)\
  • 經過化簡得到:L1+L2=nCL1=nCL2L_1+L_2=nC \to L_1=nC-L_2
  • 取出一個CCL2L_2組合:L1=(n1)C+(CL2)L_1=(n-1)C+(C-L_2) 也就是說,一開始放入A,BA,B兩指針,速度分別為 1, 2,會在距離環起點L2L_2的位置相會,
    這時將AA放到起點,走過L1L_1的距離,此時BB在裡面走了(n1)C+(CL2)(n-1)C+(C-L_2)的距離,而它一開始在交會點L2L_2
    因此現在的位置在L2+(n1)C+(CL2)=nCL_2 + (n-1)C+(C-L_2) = nC,也就是環的起點。

程式碼

快慢指針

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == nullptr || head->next == nullptr || head->next->next == nullptr) {
            return nullptr;
        }
        
        // 初始化指針
        ListNode *slow = head->next, *fast = head->next->next;
        while(slow != fast) {
            if(fast->next == nullptr || fast->next->next == nullptr) {
                // 走到終點,沒有環
                return nullptr;
            }
            slow = slow->next;
            fast = fast->next->next;
        }
        // 重回起點,找到交會點 (必定是環的起點)
        slow = head;
        while(slow != fast) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow;
    }
};

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(1)O(1)

顯示設定

背景線條
顯示背景網格線條
懸停發光
滑鼠懸停時顯示霓虹效果
聚光燈
跟隨滑鼠的聚光燈效果
背景透明度
開啟透明玻璃效果
主題顏色
自訂主要顏色