環形鏈表入口節點


環形鏈表入口節點

題目描述

思路分析:判斷是否有環

本題是判斷環形鏈表是否有環的進階題目。

環形鏈表題目利用了雙指針技巧,設置快慢兩個指針,每次快指針走兩步慢指針走一步。假如鏈表有環,那么快慢指針在環的部分終究會相遇。

判斷鏈表是否有環,比較簡單直接上代碼。

public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }

思路分析:如何找出入口節點?

方便分析作圖如下,假設a是鏈表頭節點,b是鏈表中環的入口節點,c是快慢指針相遇的節點。

三段路徑長度按順時針分別稱為ab,bc,cb。鏈表中環長度為s = bc + cb。

我們需要計算,在c點相遇的時候,快慢指針分別走了多遠?利用快慢指針長度的兩倍關系去求解問題。

快指針到c點走過的長度 s1 = ab + bc + n * s = ab + bc + n * (bc + cb)

快指針走的距離包括ab+bc的距離,再加上在圓環中環繞圈數的距離。

那么慢指針的長度如何計算?他在環中也走了多少圈?

這就需要理解一個概念:

從慢指針進入環時,到快慢指針相遇,慢指針走過的距離是一定小於等於環的大小。(如果整個鏈表是一個環,則慢指針走過距離等於環大小)
慢指針進入環后,可以看成快指針在后面追趕慢指針。

  • 最好情況快指針就在b的左側,移動一步兩者便相遇。
  • 最差情況為快指針在b的右側,需要多繞不到一圈的距離。

分析最差情況:假設慢指針走了一整圈環,回到b點時快指針才追上,慢指針移動長度為s,快指針移動長度則為2s-1。但實際上快指針速度是慢指針兩倍,即實際應走距離為2s。可以反證出在慢指針走完一圈之前,快指針必然追上慢指針。

理解了上述概念,可以很快得出,慢指針長度 s2 = ab + bc

已知了快指針是慢指針兩倍,即 2 *(ab + bc) = ab + bc + n * (bc + cb)

推出:ab = (n-1) * (bc + cb) + cb

含義為:鏈表頭到環入口的距離=相遇點到環入口的距離+(n-1)圈環長度

分析到這里,其實已經得出答案了。兩個鏈表相遇后,一個指針指向相遇的位置,一個指針指到鏈表的頭節點。兩個指針均向后移動,判斷當兩者相同時,該節點便是鏈表到環的入口節點。

代碼參考:

 public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }

        // 步驟一:使用快慢指針判斷鏈表是否有環
        ListNode fast = head;
        ListNode slow = head;
        boolean hasCycle = false;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                hasCycle = true;
                break;
            }
        }

        // 步驟二:若有環,找到入環開始的節點
        if (hasCycle) {
            ListNode cur = head;
            while (slow != cur) {
                cur = cur.next;
                slow = slow.next;
            }
            return slow;
        }

        return null;
    }

公眾號:編程囈語,分享原創優質技術文章,歡迎大家關注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM