1. 程式人生 > 其它 >每日演算法之連結串列中環的入口結點

每日演算法之連結串列中環的入口結點

JZ23 連結串列中環的入口結點

描述

給一個長度為n連結串列,若其中包含環,請找出該連結串列的環的入口結點,否則,返回null。

解析

環很大
在前面我們提到過快慢指標,判斷是否有環。如果有環,在來找環的入口。如果沒環直接返回null即可,我們假設是有環的,那麼會有兩種情況,一種是O型,一種是6型,其實原理都一樣,這裡主要看一下6字型的環,他會有兩種情況,
如果有環,那麼快指標走過的路徑就是圖中a+b+c+b,慢指標走過的路徑就是圖中a+b,因為在相同的時間內,快指標走過的路徑是慢指標的2倍,所以這裡有a+b+c+b=2*(a+b),整理得到a=c
在相遇的時候再使用兩個指標,一個從連結串列起始點開始,一個從相遇點開始,每次他們都走一步,直到再次相遇,那麼這個相遇點就是環的入口。

環很小
這種情況下當快慢指標在環上相遇的時候,快指標有可能在環上轉了好幾圈,我們假設相遇的時候快指標已經在環上轉了n圈。
那麼相遇的時候快指標走過的路徑就是a+b+(b+c)*n,(b+c其實就是環的長度),慢指標走過的路徑是a+b。由於相同時間內快指標走過的路徑是慢指標的2倍。
所以有a+b+(b+c)n=2(a+b),整理得到a+b=n*(b+c),也就是說a+b等於n個環的長度。
我們還可以使用兩個指標,一個從連結串列的起點開始,一個從相遇點開始,那麼就會出現一種情況就是,一個指標在路徑a上走,一個指標一直在環上轉圈,最終會走到第一種情況。

程式碼

package mid.JZ23連結串列中環的入口結點;

class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode slow = hasCycle(pHead);
        if (slow == null) return null;

        //快的回到起點
        ListNode fast = pHead;
        while(fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }

    /**
     * 判斷連結串列是否有環
     * @param head
     * @return
     */
    public ListNode hasCycle(ListNode head) {
        if (head == null) return null;

        ListNode fast = head;
        ListNode slow = head;

        while(fast != null && fast.next != null) {
            //快的走兩步
            fast = fast.next.next;
            //慢的走一步
            slow = slow.next;

            //如果相同返回慢的指標
            if (fast == slow) return slow;
        }
        return null;
    }
}