【判環(huán)】Floyd 龜兔賽跑算法

一、算法介紹

Floyd 龜兔賽跑算法(也稱(chēng)為 Floyd 判圈算法Floyd 循環(huán)檢測(cè)算法
是一種用于檢測(cè)鏈表中是否存在環(huán)的算法。如果鏈表上存在環(huán),那么在環(huán)上以不同速度前進(jìn)的兩個(gè)指針必定會(huì)在某個(gè)時(shí)刻相遇。

1.判斷是否有環(huán)

龜一次走一步,兔子一次走兩步:

  • 當(dāng)兔子能走到終點(diǎn)時(shí),不存在環(huán)
  • 當(dāng)兔子能追上龜時(shí),存在環(huán)

2.尋找環(huán)入口

從它們第一次相遇開(kāi)始,龜回到起點(diǎn),兔子保持原位不變

  • 龜和兔子一次都走一步
  • 當(dāng)再次相遇時(shí),地點(diǎn)就是環(huán)的入口

設(shè)起點(diǎn)到環(huán)入口長(zhǎng)度為x步,環(huán)的長(zhǎng)度為y步,那么x+ny步的長(zhǎng)度為環(huán)的入口處。(因?yàn)榄h(huán)的長(zhǎng)度是y,一個(gè)y就是從起點(diǎn)到終點(diǎn),n個(gè)y就是重疊了n次,還是在入口處)

第一次相遇龜和兔走的路程:

  • S_兔=x+n_1y+z(必須是在繞環(huán)的過(guò)程中才能追上龜)
  • S_龜=x+n_2y+zn_2<n_1

因?yàn)橥米拥木嚯x是烏龜?shù)膬杀叮ㄍ米右淮?步,烏龜一次1步),所以:
S_兔-S_龜=S_龜
(x+n_1y+z)-(x+n_2y+z)=S_龜=(n_1-n_2)y

所以烏龜走的距離正好是整數(shù)倍的環(huán)長(zhǎng)度,即ny。
根據(jù)前面環(huán)入口處的長(zhǎng)度為x+ny,所以,在烏龜和兔子相遇之后,烏龜只需要再走x步,此時(shí)距離就為x+ny,即環(huán)入口的長(zhǎng)度。

此時(shí),要計(jì)算出x為具體為多少,可以讓兔子模擬烏龜(即每次只走一步),那么兔子需要前進(jìn)x步走到環(huán)入口;讓烏龜回到起點(diǎn),烏龜前進(jìn)x步也能走到環(huán)入口,所以x的值就是他們相遇時(shí)候所走的步數(shù);即相遇的點(diǎn)就是環(huán)的入口。

二、Leetcode141.環(huán)形鏈表(判斷是否有環(huán))

判斷是否有環(huán):
使用兩個(gè)指針,一個(gè)快指針和一個(gè)慢指針,分別以不同的速度遍歷鏈表,兩個(gè)指針相遇代表有環(huán),否則無(wú)環(huán)。

    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }

        ListNode fast = head;
        ListNode slow = head;

        while (true) {
            fast = fast.next.next;
            slow = slow.next;
            // 有環(huán)
            if (fast == slow) {
                return true;
            }
            // 無(wú)環(huán)
            if (fast == null || fast.next == null) {
                return false;
            }
        }
    }

三、Leetcode142.環(huán)形鏈表II(尋找環(huán)入口)

尋找環(huán)的入口:
在第一次相遇后,將 slow 指針重新指向鏈表頭節(jié)點(diǎn),然后 slow 和 fast 指針都以相同的速度(每次移動(dòng)一步)前進(jìn),當(dāng)它們?cè)俅蜗嘤鰰r(shí),相遇點(diǎn)即為環(huán)的入口點(diǎn)。

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

        ListNode fast = head;
        ListNode slow = head;

        while (true) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                // 相遇 讓slow回到起點(diǎn)
                slow = head;
                while (fast != slow) {
                    // 分別前進(jìn)一步
                    fast = fast.next;
                    slow = slow.next;
                }
                return slow;
            }
            if (fast == null || fast.next == null) {
                return null;
            }
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容