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

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

問題:oop

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

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

  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。【計算了環大小】

核心代碼code

尋找環入口

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;
}

計算環大小blog

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;
    }
相關文章
相關標籤/搜索