【證明】快慢指針判斷鏈表有環、尋找環入口、計算環大小的原理

轉載:https://blog.csdn.net/donghuaan/article/details/78988987

問題:

給定一個鏈表: 
1. 判斷鏈表是否有環。 
2. 如果鏈表有環,請找出環入口。 
3. 計算環的大小。

思路:快慢指針
        分別定義一個快指針fast和慢指針slow,快指針一次走兩步,慢指針一次走一步。如果鏈表沒有環,那麼fast最終會指向nullptr;如果鏈表有環,那麼快指針和慢指針最終會相遇。所以,如果最終fast == nullptr,那麼判斷鏈表無環;如果最終fast == slow,且fast != nullptr,那麼鏈表有環。

  1. 第一步:快慢指針從頭結點出發。如下圖所示。藍色表示快指針fast,紅色表示慢指針slow。

【證明】快慢指針判斷鏈表有環、尋找環入口、計算環大小的原理

  1. 第二步:慢指針slow走到了環入口,共走了k步。此時快指針fast越過了環入口的步數爲delta。因爲快指針可能繞着環走了很多圈,所以有k == delta + n * R,其中R爲環的大小,n爲快指針繞環走的步數。

【證明】快慢指針判斷鏈表有環、尋找環入口、計算環大小的原理

  1. 第三步:慢指針進入環中。因爲快指針每次都比慢指針快一步,所以,快慢指針最後一定會相遇。【證明了必然會相遇】

  2. 第四步:計算快慢指針相遇位置。因爲慢指針在剛進入環時距離快指針delta步,所以快指針還需要比慢指針多走R - delta步才能與慢指針相遇。又因爲快指針每次走兩步,所以快指針還需要走2(R - delta)步。那麼,相遇位置爲2(R - delta) + delta == 2R - delta,即,距離環入口delta處,與慢指針剛進入環時快指針所在位置對稱。

【證明】快慢指針判斷鏈表有環、尋找環入口、計算環大小的原理

  1. 第五步:快指針重新從頭結點開始走,速度爲一次一步,與慢指針相同。可知,快指針走到環入口時,所需步數爲k。剛好,k == delta + n * R,這也是慢指針在環中所走的距離。由快慢指針在環中的相遇位置可知,慢指針此時剛好走到了環入口,並與快指針相遇,此時,找到了環入口。【證明了能找到環入口。】

【證明】快慢指針判斷鏈表有環、尋找環入口、計算環大小的原理

  1. 第六步:如何求環大小。這個相對簡單,在證明鏈表是否有環的過程中,快慢指針第一次相遇。此後,快指針繼續按一次兩步的速度走,慢指針按一次一步的速度走,並設置一個計數器count = 0,每走一次加1,。當快慢指針再次相遇時,快指針剛好比慢指針多走了R步,而計數器count == R。【計算了環大小】

核心代碼

尋找環入口

LLNode * LinkedList::entranceOfLoop()
{
        LLNode * slow = pHead;
        LLNode * fast = pHead;

        while(fast && fast->pNext)
        {
                fast = fast->pNext->pNext;
                slow = slow->pNext;
                if(fast == slow) break;
        }

        if(!fast || !fast->pNext) return nullptr;

        fast = pHead;
        while(fast != slow)
        {
                fast = fast->pNext;
                slow = slow->pNext;
        }

        return fast;
}

計算環大小

    int LinkedList::sizeOfLoop()
    {
            LLNode * slow = pHead;
            LLNode * fast = pHead;

            while(fast && fast->pNext)
            {
                    fast = fast->pNext->pNext;
                    slow = pNext;
                    if(fast == slow) break;
            }

            if(!fast || !fast->pNext) return 0;

            int size = 1;
            fast = fast->pNext->pNext;
            slow = slow->pNext;
            while(fast != slow)
            {
                    ++size;
                    fast = fast->pNext->pNext;
                    slow = slow->pNext;
            }

            return size;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章