編程之美-判斷兩個(gè)鏈表是否相交 (涵其擴(kuò)展問題)

問題定義

兩個(gè)單向鏈表的頭指針,兩個(gè)鏈表都可能帶環(huán)
1: 判斷這兩個(gè)鏈表是否相交
2: 如果相交,給出他們相交的第一個(gè)節(jié)點(diǎn)。

無環(huán)情況

判斷鏈表是否相交

單鏈表相交似踱,意味著相交結(jié)點(diǎn)具有相同的內(nèi)存地址,且相交結(jié)點(diǎn)后的所有結(jié)點(diǎn)是兩個(gè)鏈表共有的稽煤。
方法一:


Paste_Image.png

如果兩條單鏈表相交核芽,則將鏈表B,連接到鏈表A后面酵熙,如圖所示(上面的鏈表是A轧简,下面的鏈表是B),會(huì)形成環(huán)路匾二,且鏈表B的表頭一定在環(huán)上哮独。因此我們只需要從鏈表B開始遍歷拳芙,如果可以回到鏈表B的頭結(jié)點(diǎn),則說明兩條鏈表相交皮璧。
時(shí)間復(fù)雜度:O(len(A)+len(B))
代碼如下:

// 結(jié)點(diǎn)
static class ListNode{
        int value;
        ListNode next;
    }
static boolean isIntersect1(ListNode h1, ListNode h2){
        boolean isinter = false;
        ListNode p1 = h1, p2 = h2;
        if(p1==null || h2==null) return false;
        // find the end node of list p1
        while(p1.next != null) p1 = p1.next;
        
        // append list p2 on the tail of p1
        p1.next = p2;
        
        // enumerate list p2 from its header
        while(p2 != null){
            if(p2 == h2) {
                isinter = true;
                break;
            }
            p2 = p2.next;
        }

        return isinter;
    }

方法二:
單鏈表相交舟扎,意味著相交結(jié)點(diǎn)具有相同的內(nèi)存地址,且相交結(jié)點(diǎn)后的所有結(jié)點(diǎn)是兩個(gè)鏈表共有的悴务。因此如果兩個(gè)鏈表相交睹限,則最后一個(gè)節(jié)點(diǎn)肯定是相同的,因此只需要判斷兩個(gè)鏈表的最優(yōu)一個(gè)節(jié)點(diǎn)是否相同讯檐。
時(shí)間復(fù)雜度: O(len(A)+len(B))

代碼如下:

static boolean isIntersect2(ListNode h1, ListNode h2){
        ListNode p1 = h1, p2 = h2;
        if(p1==null || h2==null) return false;
        ListNode last1 = p1;
        while(p1.next != null){
            last1 = p1;
            p1 = p1.next;
        }
        ListNode last2 = p2;
        while (p2.next != null){
            last1 = p2;
            p2 = p2.next;
        }
        if(last1==last2){
            return true;
        }else return false;

    }

尋找鏈表的第一個(gè)交點(diǎn)

先讓計(jì)算鏈表的長度羡疗,讓最長的鏈表A先走 len(A)-len(B)步,然后兩個(gè)鏈表一起走别洪,第一個(gè)相交點(diǎn)叨恨,即為所求的點(diǎn)。

static ListNode findFisrtCrossNode(ListNode h1, ListNode h2){
        int lenA = len(h1);
        int lenB = len(h2);
        ListNode p1 = h1, p2 = h2;
        ListNode tmp = null;
        if(lenA > lenB) tmp = p1;
        else tmp = p2;
        for(int i=0; i<Math.abs(lenA-lenB); ++i){
            tmp = tmp.next;
        }
        if(lenA > lenB) p1=tmp;
        else p2 = tmp;
        
        while(p1!=null && p2!=null){
            if(p1==p2) return p1;
            p1 = p1.next;
            p2 = p2.next;
        }
        return null;
    }
static int len(ListNode h){
        int clen = 0;
        ListNode p = h;
        while (p!=null){
            p = p.next;
            ++clen;
        }
        return clen;
    }

有環(huán)情況

判斷鏈表是否有環(huán)

追逐法:
設(shè)置兩個(gè)指針 fast, slow蕉拢,將其初始化為鏈表的頭結(jié)點(diǎn)特碳;然后兩個(gè)節(jié)點(diǎn)同時(shí)向前移動(dòng)诚亚,fast一次移動(dòng)2步晕换,slow一次移動(dòng)一步。如果存在環(huán)站宗,fast指針和slow指針一定相遇闸准。

static boolean hasCycle(ListNode h){
        ListNode fast=h, slow=h;

        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow && slow!=null){
                return true;
            }
        }
        return false;
 }

尋找環(huán)在鏈表上的入口點(diǎn)

Paste_Image.png

當(dāng)fast與slow相遇時(shí),假設(shè)slow在環(huán)內(nèi)循環(huán)了n次梢灭,fast在環(huán)內(nèi)循環(huán)了m次夷家,顯然n>m,且m為0 (若有環(huán)存在敏释,fast 必然在slow繞環(huán)一周之前與slow相遇库快。考慮極端情況钥顽,slow走到環(huán)入口節(jié)點(diǎn)時(shí)义屏,fast位于slow前面的一個(gè)節(jié)點(diǎn),記為n0蜂大,此時(shí)fast以slow指針2倍的速度繞環(huán)闽铐,當(dāng)fast指針追上slow指針時(shí), nr/2v = mr/v ==> n/2 = m == n=2m, 即當(dāng)slow繞環(huán)第一周后,回到環(huán)入口節(jié)點(diǎn)奶浦,n=2兄墅, 已經(jīng)繞環(huán)兩周,并回到n0節(jié)點(diǎn)澳叉,由于fast指針步長等于slow的2倍隙咸,則fast指針和slow指針必然再環(huán)入口節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)相遇)
如上圖所示沐悦,當(dāng)slow指針和fast直接相遇時(shí)(定義此時(shí)的節(jié)點(diǎn)為相遇結(jié)點(diǎn)),相遇后五督,另p1指向頭結(jié)點(diǎn)所踊,p2指向相遇節(jié)點(diǎn),設(shè)頭結(jié)點(diǎn)距離環(huán)入口節(jié)點(diǎn)的距離:a, 頭結(jié)點(diǎn)距離相遇節(jié)點(diǎn)的距離: s=a+x, 環(huán)周長:r=x+y概荷。讓p1秕岛、p2指針每次移動(dòng)一步,當(dāng)p1==p2時(shí)误证,此時(shí)就是p1(p2)指向的節(jié)點(diǎn)就是環(huán)入口節(jié)點(diǎn)继薛。
假設(shè)在fast與slow重合時(shí)fast已繞環(huán)n周(n>0),且此時(shí)slow移動(dòng)總長度為m愈捅,則fast移動(dòng)總長度為2m遏考。
2m = m+ nr = m + n(x+y) ==> m = n(x+y)
m = a+x
==> a+x = n(x+y)
==> a= n(x+y) - x = nr - x
指針p1從鏈表起點(diǎn)處開始遍歷,指針p2從相遇節(jié)點(diǎn)處開始遍歷蓝谨,且p1和p2移動(dòng)步長均為1灌具。則當(dāng)p1移動(dòng) a 步即到達(dá)環(huán)的入口點(diǎn),由上式可知譬巫,此時(shí)p2也已移動(dòng) a 步即nr - x步咖楣。由于p2是從相遇節(jié)點(diǎn)處開始移動(dòng),故p2移動(dòng)nr步是移回到了相遇節(jié)點(diǎn)處芦昔,再退 x 步則是到了環(huán)的入口點(diǎn)
該公式表明:從鏈表頭和相遇點(diǎn)分別設(shè)一個(gè)指針诱贿,每次各走一步,這兩個(gè)指針必定相遇咕缎,且相遇的第一個(gè)點(diǎn)為環(huán)入口點(diǎn)珠十。

代碼如下:

static ListNode findCycleEntry(ListNode h){
        ListNode fast=h, slow=h;
        ListNode meetNode = null;
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow && slow!=null){
                meetNode = slow;
                break;
            }
        }
        ListNode p = h;
        while(p!=null && meetNode!=null){
            if(p==meetNode){
                return p;
            }
            p = p.next;
            meetNode = meetNode.next;
        }
        return null;
    }

找出帶環(huán)的兩條鏈表相交的第一個(gè)節(jié)點(diǎn)

分兩種情況:
1、只有一條鏈表帶環(huán)凭豪,此時(shí)兩條鏈表不可能相交焙蹭;否則,由于相交結(jié)點(diǎn)后的所有結(jié)點(diǎn)由兩條鏈表共享嫂伞,因此導(dǎo)致另一條不帶環(huán)的鏈表卻出現(xiàn)環(huán)孔厉,導(dǎo)出相悖的結(jié)論。
2末早、兩條鏈表都帶環(huán)烟馅。如果兩條鏈表相交,則他們共享同一個(gè)環(huán)然磷!

Paste_Image.png

帶環(huán)鏈表相交郑趁,如圖所示,存在兩種情況:
1姿搜、交點(diǎn)在環(huán)中
2寡润、交點(diǎn)不在環(huán)中

參考文獻(xiàn)中對(duì)該問題的解決辦法是首先找兩個(gè)鏈表的相遇點(diǎn)捆憎,但由于相遇點(diǎn)值存在于環(huán)中(利用fast,slow指針的方式得到的相遇點(diǎn)),因此其方法不能解決交點(diǎn)不在環(huán)中的情況梭纹。

解決方法
第一步:分別找出兩個(gè)鏈表的環(huán)入口點(diǎn)pos1, pos2躲惰;
第二步:如果pos1==pos2, 屬于第二種情況:交點(diǎn)不在環(huán)中。然后以pos1作為兩條鏈表的終點(diǎn)变抽,利用求不帶環(huán)單鏈表交點(diǎn)的方法求出交點(diǎn)础拨。
第三步:如果pos1!=pos2, 從pos1開始遍歷環(huán)中的節(jié)點(diǎn),如果沒有發(fā)現(xiàn)有節(jié)點(diǎn)與pos2相等绍载,則說明兩條鏈表沒有交點(diǎn)诡宗,否則,存在交點(diǎn)
第四步:分別以pos1和pos2作為終止節(jié)點(diǎn)击儡,用求不帶環(huán)單鏈表交點(diǎn)的方法求解塔沃。其中,必然一個(gè)有解阳谍,一個(gè)無解蛀柴。取有解的那一組作為我們的答案。

參考文章:

http://blog.csdn.net/linyunzju/article/details/7753548

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矫夯,一起剝皮案震驚了整個(gè)濱河市鸽疾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茧痒,老刑警劉巖肮韧,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異旺订,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)超燃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門区拳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人意乓,你說我怎么就攤上這事樱调。” “怎么了届良?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵笆凌,是天一觀的道長。 經(jīng)常有香客問我士葫,道長乞而,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任慢显,我火速辦了婚禮爪模,結(jié)果婚禮上欠啤,老公的妹妹穿的比我還像新娘。我一直安慰自己屋灌,他們只是感情好洁段,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著共郭,像睡著了一般祠丝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上除嘹,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天纽疟,我揣著相機(jī)與錄音,去河邊找鬼憾赁。 笑死污朽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的龙考。 我是一名探鬼主播蟆肆,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼晦款!你這毒婦竟也來了炎功?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤缓溅,失蹤者是張志新(化名)和其女友劉穎蛇损,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坛怪,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淤齐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袜匿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片更啄。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖居灯,靈堂內(nèi)的尸體忽然破棺而出祭务,到底是詐尸還是另有隱情,我是刑警寧澤怪嫌,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布义锥,位于F島的核電站,受9級(jí)特大地震影響岩灭,放射性物質(zhì)發(fā)生泄漏拌倍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一川背、第九天 我趴在偏房一處隱蔽的房頂上張望贰拿。 院中可真熱鬧蛤袒,春花似錦、人聲如沸膨更。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荚守。三九已至珍德,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矗漾,已是汗流浹背锈候。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敞贡,地道東北人泵琳。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像誊役,于是被迫代替她去往敵國和親获列。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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