【刷題】Linked List Cycle II

原題戳我

題目

Description

Given a linked list, return the node where the cycle begins.

If there is no cycle, return null.

Example

Given -21->10->4->5, tail connects to node index 1荠瘪,return 10

Challenge

Follow up:

Can you solve it without using extra space?

分析

問題分解

basic problem

單鏈表中確定有無環(huán)

暴力方法是使用hash表統(tǒng)計(jì)節(jié)點(diǎn)的出現(xiàn)次數(shù)请契,O(n)的space冰肴。不過一般是希望以O(shè)(1)的space解決:

  1. 設(shè)置一個快指針fast和一個慢指針slow绒净,它們同時從鏈表頭開始往后遍歷褪迟,快指針每次移動兩個位置,慢指針每次移動一個位置
  2. 如果在快指針訪問到null(即無環(huán))之前虽填,快指針和慢指針相遇蔬咬,就說明有環(huán)

follow up

確定環(huán)入口入口的位置

和basic problem一樣,可以用hash表解決谚中。而follow up的目的仍然是希望O(1)的space解決:

  1. 重復(fù)上述判定有環(huán)無環(huán)的過程
  2. 用一個新指針指向head渴杆,與slow指針同時一次移動一個位置
  3. 當(dāng)head與slow相遇時,指針?biāo)傅墓?jié)點(diǎn)即入口節(jié)點(diǎn)

證明

相遇一定有環(huán)

反證法:

如果無環(huán),則fast一定比slow先到達(dá)null,不會相遇贡必。因此,如果fast與slow相遇比搭,則一定有環(huán)。

得證南誊。

第一次相遇一定發(fā)生在slow第一次入環(huán)的過程中

該結(jié)論是下一步推導(dǎo)的前提身诺。

設(shè)鏈表頭節(jié)點(diǎn)為head蜜托,環(huán)入口節(jié)點(diǎn)為entrance,head到entrance共有n個節(jié)點(diǎn)霉赡,環(huán)上共有m個節(jié)點(diǎn)橄务。顯然,fast和slow相遇的節(jié)點(diǎn)一定在環(huán)中同廉,設(shè)從entrance到這個節(jié)點(diǎn)共k個節(jié)點(diǎn)仪糖。

PS:代碼實(shí)現(xiàn)時柑司,需要關(guān)注m迫肖、n、k等計(jì)算時是否包含head攒驰、entrance等蟆湖,但證明時無需關(guān)心,僅僅是加減一個常數(shù)項(xiàng)的事情玻粪。

fast的速度是slow的兩倍隅津。則,fast第一次到entrance時劲室,slow到達(dá)鏈表中部節(jié)點(diǎn)mid伦仍,設(shè)head到mid共有s個節(jié)點(diǎn),則此時很洋,slow走了s個節(jié)點(diǎn)充蓝,fast走了2s個節(jié)點(diǎn)。我們讓slow再走s個節(jié)點(diǎn)喉磁,fast再走2s個節(jié)點(diǎn)谓苟,分情況討論:

如果entrance等于head

此情況下環(huán)最長。經(jīng)過s個節(jié)點(diǎn)协怒,slow恰好第一次到達(dá)entrance涝焙;經(jīng)過2s個節(jié)點(diǎn),fast恰好第二次到達(dá)entrance孕暇。在此過程中仑撞,slow有且僅有一次從mid走到entrance,fast有且僅有一次從head經(jīng)過mid走到entrance妖滔,從而隧哮,fast與slow必然有且僅有一次在mid于entrance之間相遇,這是二者第一次相遇铛楣。由于相遇點(diǎn)一定在環(huán)中近迁,因此第一次相遇一定發(fā)生在slow第一次入環(huán)的過程中

如果entrance不等于head

此情況下簸州,環(huán)均比第一種情況短鉴竭。重復(fù)上述過程歧譬,slow仍然有且僅有一次從mid走到entrance,但fast卻由于環(huán)的縮短搏存,可能不止一次與slow相遇并走到entrance瑰步。我們只關(guān)注第一次相遇,顯然璧眠,第一次相遇仍然發(fā)生在slow第一次入環(huán)的過程中缩焦。

得證。

如何尋找入口節(jié)點(diǎn)

我們現(xiàn)在知道责静,“第一次相遇一定發(fā)生在slow第一次入環(huán)的過程中”袁滥,那么此時slow共走了n+k個節(jié)點(diǎn),fast共移動了n+k + x*m個節(jié)點(diǎn)灾螃。fast速度是slow的2倍题翻,則有2*(n+k) = n+k + x*m,其中x表示fast已經(jīng)在環(huán)中走的圈數(shù)腰鬼。由此可得嵌赠,n+k = x*m,從而n = (x-1)*m + m-k(x>=1, m>=k)熄赡。

在有環(huán)鏈表中姜挺,我們只能基于移動和相遇進(jìn)行判斷。basic problem中彼硫,我們希望通過相遇判斷是否有環(huán)炊豪,follow up中,可以試著用相遇找到entrance節(jié)點(diǎn)乌助。

觀察式n = (x-1)*m + m-k

  • n為head到entrance的節(jié)點(diǎn)數(shù)
  • m為環(huán)的長度
  • m-k為從fast溜在、slow的相遇點(diǎn)到entrance的節(jié)點(diǎn)數(shù)

如果讓slow繼續(xù)走m-k個節(jié)點(diǎn),此時slow將恰好位于entrance他托;再循環(huán)y = x-1圈掖肋,仍然處于entrance。增加一個新的指針p = head赏参,則可以這樣理解上式:使p和slow同時開始移動(slow從剛才的相遇點(diǎn)開始)志笼,都一次移動一個位置,則當(dāng)p第一次經(jīng)過n個節(jié)點(diǎn)走到entrance時把篓,slow恰好先經(jīng)過了m-k個節(jié)點(diǎn)纫溃,再走了整y圈回到entrance

此時韧掩,p與slow相遇紊浩,相遇點(diǎn)即為entrance。

代碼

/**
 * Definition for ListNode.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int val) {
 *         this.val = val;
 *         this.next = null;
 *     }
 * }
 */ 
public class Solution {
    /**
     * @param head: The first node of linked list.
     * @return: The node where the cycle begins. 
     *           if there is no cycle, return null
     */
    public ListNode detectCycle(ListNode head) {  
        // write your code here
        if (head == null) {
            return null;
        }
        
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                break;
            }
        }
        if (fast == null || fast.next == null) {
            return null;
        }
        
        ListNode p = head;
        while (p != slow) {
            p = p.next;
            slow = slow.next;
        }
        return p;
    }
}

本文鏈接:【刷題】Linked List Cycle II
作者:猴子007
出處:https://monkeysayhi.github.io
本文基于 知識共享署名-相同方式共享 4.0 國際許可協(xié)議發(fā)布,歡迎轉(zhuǎn)載坊谁,演繹或用于商業(yè)目的费彼,但是必須保留本文的署名及鏈接。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末口芍,一起剝皮案震驚了整個濱河市箍铲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鬓椭,老刑警劉巖颠猴,帶你破解...
    沈念sama閱讀 212,686評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異小染,居然都是意外死亡翘瓮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評論 3 385
  • 文/潘曉璐 我一進(jìn)店門氧映,熙熙樓的掌柜王于貴愁眉苦臉地迎上來春畔,“玉大人,你說我怎么就攤上這事岛都。” “怎么了振峻?”我有些...
    開封第一講書人閱讀 158,160評論 0 348
  • 文/不壞的土叔 我叫張陵臼疫,是天一觀的道長。 經(jīng)常有香客問我扣孟,道長烫堤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,736評論 1 284
  • 正文 為了忘掉前任凤价,我火速辦了婚禮鸽斟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘利诺。我一直安慰自己富蓄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評論 6 386
  • 文/花漫 我一把揭開白布慢逾。 她就那樣靜靜地躺著立倍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侣滩。 梳的紋絲不亂的頭發(fā)上口注,一...
    開封第一講書人閱讀 50,043評論 1 291
  • 那天,我揣著相機(jī)與錄音君珠,去河邊找鬼寝志。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的材部。 我是一名探鬼主播悠菜,決...
    沈念sama閱讀 39,129評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼败富!你這毒婦竟也來了悔醋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,872評論 0 268
  • 序言:老撾萬榮一對情侶失蹤兽叮,失蹤者是張志新(化名)和其女友劉穎芬骄,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹦聪,經(jīng)...
    沈念sama閱讀 44,318評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡账阻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了泽本。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淘太。...
    茶點(diǎn)故事閱讀 38,777評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖规丽,靈堂內(nèi)的尸體忽然破棺而出蒲牧,到底是詐尸還是另有隱情,我是刑警寧澤赌莺,帶...
    沈念sama閱讀 34,470評論 4 333
  • 正文 年R本政府宣布冰抢,位于F島的核電站,受9級特大地震影響艘狭,放射性物質(zhì)發(fā)生泄漏挎扰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評論 3 317
  • 文/蒙蒙 一巢音、第九天 我趴在偏房一處隱蔽的房頂上張望遵倦。 院中可真熱鬧,春花似錦官撼、人聲如沸梧躺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽燥狰。三九已至,卻和暖如春斜筐,著一層夾襖步出監(jiān)牢的瞬間龙致,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評論 1 267
  • 我被黑心中介騙來泰國打工顷链, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留目代,地道東北人。 一個月前我還...
    沈念sama閱讀 46,589評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像榛了,于是被迫代替她去往敵國和親在讶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評論 2 351

推薦閱讀更多精彩內(nèi)容