劍指offer—— 復(fù)雜鏈表復(fù)制

題目:

輸入一個(gè)復(fù)雜鏈表(每個(gè)節(jié)點(diǎn)中有節(jié)點(diǎn)值,以及兩個(gè)指針痪署,一個(gè)指向下一個(gè)節(jié)點(diǎn)码泞,另一個(gè)特殊指針random指向一個(gè)隨機(jī)節(jié)點(diǎn)),請(qǐng)對(duì)此鏈表進(jìn)行深拷貝狼犯,并返回拷貝后的頭結(jié)點(diǎn)余寥。(注意,輸出結(jié)果中請(qǐng)不要返回參數(shù)中的節(jié)點(diǎn)引用悯森,否則判題程序會(huì)直接返回空)

第一種方法

思路:

  • (1)將鏈表中的節(jié)點(diǎn)用列表存儲(chǔ)
  • (2)然后遍歷查找每個(gè)節(jié)點(diǎn)中random指向列表中的哪一個(gè)節(jié)點(diǎn)對(duì)象宋舷,并按照列表順序存儲(chǔ)節(jié)點(diǎn)random指向的節(jié)點(diǎn)對(duì)象的下標(biāo)。
  • (3)創(chuàng)建新節(jié)點(diǎn)列表
  • (4)將新節(jié)點(diǎn)中的next和random進(jìn)行鏈接呐馆。
1587908166698.png

代碼:

import java.util.ArrayList;

public class Solution1 {
    public class RandomListNode {
        int label;
        RandomListNode next = null;
        RandomListNode random = null;

        RandomListNode(int label) {
            this.label = label;
        }
    }
    public ArrayList<RandomListNode> toArray(RandomListNode pHead){
        if(pHead==null){
            return null;
        }
        ArrayList<RandomListNode> result=new ArrayList<RandomListNode>();
        RandomListNode key=pHead;
        while(key!=null){
            result.add(key);
            key=key.next;
        }
        return result;
    }
    public int getRandomIndex(ArrayList<RandomListNode> oldNode,RandomListNode key){
        for(int i=0;i<oldNode.size();i++){
            if(oldNode.get(i).equals(key)){
                return i;
            }
        }
        return -1;
    }
    public int[] getRandomList(ArrayList<RandomListNode> oldNode){
        int [] result=new int[oldNode.size()];
        for(int i=0;i<oldNode.size();i++){
            result[i]=this.getRandomIndex(oldNode,oldNode.get(i).random);
            System.out.println(result[i]);
        }
        return result;
    }
    public RandomListNode copyNode(RandomListNode old){
        return new RandomListNode(old.label);
    }
    public ArrayList<RandomListNode> getNewList(ArrayList<RandomListNode> oldNode){
        ArrayList<RandomListNode> newNode=new ArrayList<>();
        for(int i=0;i<oldNode.size();i++){
            newNode.add(this.copyNode(oldNode.get(i)));
        }
        return newNode;
    }
    public RandomListNode getNewLink(ArrayList<RandomListNode> newNode,int [] randomList){

        RandomListNode root=newNode.get(0);
        RandomListNode key=root;
        for(int i=1;i<newNode.size();i++){
            key.next=newNode.get(i);
            key=key.next;
        }
        for(int i=0;i<randomList.length;i++){
            if(randomList[i]!=-1){
                newNode.get(i).random=newNode.get(randomList[i]);
            }
        }
        return root;
    }
    public RandomListNode Clone(RandomListNode pHead)
    {
        //第1步:將原始鏈表數(shù)組化 時(shí)間復(fù)雜度(n),空間復(fù)雜度(n)
        ArrayList<RandomListNode> oldNode=this.toArray(pHead);
        if(oldNode==null){
            return null;
        }
        //第2步:遍歷查詢r(jià)andom所指向的node 時(shí)間復(fù)雜度(n^2),空間復(fù)雜度(0)
        int [] randomList=this.getRandomList(oldNode);
        //第3步:根據(jù)數(shù)組重新創(chuàng)建一個(gè)新Node數(shù)組肥缔,next和random都為null 時(shí)間復(fù)雜度(n),空間復(fù)雜度(n)
        ArrayList<RandomListNode> newNode=this.getNewList(oldNode);
        //第4步:鏈接鏈表 時(shí)間復(fù)雜度(n),空間復(fù)雜度(0)
        RandomListNode newRoot=this.getNewLink(newNode,randomList);
        return newRoot;
    }
    public RandomListNode create(){
        RandomListNode r1=new RandomListNode(1);
        RandomListNode r2=new RandomListNode(2);
        RandomListNode r3=new RandomListNode(3);
        RandomListNode r4=new RandomListNode(4);
        RandomListNode r5=new RandomListNode(5);
        RandomListNode r6=new RandomListNode(6);
        RandomListNode r7=new RandomListNode(7);
        RandomListNode r8=new RandomListNode(8);
        r1.next=r2;
        r2.next=r3;
        r3.next=r4;
        r4.next=r5;
        r5.next=r6;
        r6.next=r7;
        r7.next=r8;
        r1.random=r3;
        r2.random=r4;
        r3.random=r5;
        r4.random=r6;
        r5.random=r7;
        r6.random=r8;
        r7.random=r1;
        r8.random=r2;
        return r1;
    }

    public static void main(String[] args) {
        Solution1 s=new Solution1();
        RandomListNode root=s.create();
        s.Clone(root);
    }
}

算法分析:

該方法最復(fù)雜的地方就是尋找random所指向的節(jié)點(diǎn)。

時(shí)間復(fù)雜度O(n^2),空間復(fù)雜度O(n)

代碼運(yùn)行:

運(yùn)行時(shí)間:24ms

占用內(nèi)存:9656k

第二種方法

這個(gè)題目最大的難點(diǎn)在于random引用如何便捷正確的指向?qū)?yīng)的新節(jié)點(diǎn)汹来。

本方法思路:

  • (1)依次創(chuàng)建新的節(jié)點(diǎn)插入到對(duì)應(yīng)的舊節(jié)點(diǎn)之后

  • (2)此時(shí)新節(jié)點(diǎn)的random就在舊節(jié)點(diǎn)的random后面续膳,根據(jù)這一規(guī)律,對(duì)新節(jié)點(diǎn)的random進(jìn)行賦值收班。

  • (3)將組合鏈表中舊節(jié)點(diǎn)刪除坟岔,可以借助一個(gè)額外節(jié)點(diǎn)作為暫時(shí)的根節(jié)點(diǎn)。

    1587969275319.png

代碼:

public class Solution2 {
    public class RandomListNode {
        int label;
        RandomListNode next = null;
        RandomListNode random = null;

        RandomListNode(int label) {
            this.label = label;
        }
    }
    public void insertNewNodeInLink(RandomListNode pHead){
        RandomListNode p=pHead;
        while(p!=null){
            RandomListNode q=new RandomListNode(p.label);
            q.next=p.next;
            p.next=q;
            p=q.next;
        }
    }
    public void replaceRandom(RandomListNode pHead){
        RandomListNode t=pHead;
        while(t!=null){
            RandomListNode q=t.next;
            if(t.random!=null)
                q.random=t.random.next;
            t=q.next;

        }
    }
    public RandomListNode getNewLink(RandomListNode pHead){
        RandomListNode s=new RandomListNode(0);
        RandomListNode s1=s;
        while(pHead!=null){
            RandomListNode  q=pHead.next;
            pHead.next=q.next;
            q.next=s.next;
            s.next=q;
            s=s.next;
            pHead=pHead.next;


        }
        return s1.next;
    }
    public RandomListNode Clone(RandomListNode pHead)
    {
        //第一步:遍歷創(chuàng)建新的復(fù)制節(jié)點(diǎn)摔桦,并將其插入到舊鏈表中被復(fù)制節(jié)點(diǎn)之后 時(shí)間復(fù)雜度(n),空間復(fù)雜度(0)
        this.insertNewNodeInLink(pHead);
        //第二步:因?yàn)樾鹿?jié)點(diǎn)就在舊節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)社付,因此random所指的舊節(jié)點(diǎn)向下移一個(gè)承疲,就能夠指向新節(jié)點(diǎn) 時(shí)間復(fù)雜度(n),空間復(fù)雜度(0)
        this.replaceRandom(pHead);
        //第三步:將新節(jié)點(diǎn)串聯(lián)成新的鏈表 時(shí)間復(fù)雜度(n),空間復(fù)雜度(0)
        RandomListNode newroot = this.getNewLink(pHead);

        return newroot;

    }
    public RandomListNode create(){
        RandomListNode r1=new RandomListNode(1);
        RandomListNode r2=new RandomListNode(2);
        RandomListNode r3=new RandomListNode(3);
        RandomListNode r4=new RandomListNode(4);
        RandomListNode r5=new RandomListNode(5);
        RandomListNode r6=new RandomListNode(6);
        RandomListNode r7=new RandomListNode(7);
        RandomListNode r8=new RandomListNode(8);
        r1.next=r2;
        r2.next=r3;
        r3.next=r4;
        r4.next=r5;
        r5.next=r6;
        r6.next=r7;
        r7.next=r8;
        r1.random=r3;
        r2.random=r4;
        r3.random=r5;
        r4.random=r6;
        r5.random=r7;
        r6.random=r8;
        r7.random=r1;
        r8.random=r2;
        return r1;

    }

    public static void main(String[] args) {
        Solution2 s=new Solution2();
        RandomListNode root=s.create();
        RandomListNode t=s.Clone(root);

        while(t!=null){
            System.out.println(t.label);
            t=t.next;
        }
    }
}

算法分析

空間復(fù)雜度:O(0)

時(shí)間復(fù)雜度:O(n)

運(yùn)行代碼:

運(yùn)行時(shí)間:19ms

占用內(nèi)存:9428k

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鸥咖,隨后出現(xiàn)的幾起案子燕鸽,更是在濱河造成了極大的恐慌,老刑警劉巖啼辣,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啊研,死亡現(xiàn)場離奇詭異,居然都是意外死亡鸥拧,警方通過查閱死者的電腦和手機(jī)党远,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來富弦,“玉大人沟娱,你說我怎么就攤上這事⊥蠊瘢” “怎么了济似?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長媳握。 經(jīng)常有香客問我碱屁,道長,這世上最難降的妖魔是什么蛾找? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮赵誓,結(jié)果婚禮上打毛,老公的妹妹穿的比我還像新娘。我一直安慰自己俩功,他們只是感情好幻枉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著诡蜓,像睡著了一般熬甫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蔓罚,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天椿肩,我揣著相機(jī)與錄音,去河邊找鬼豺谈。 笑死郑象,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茬末。 我是一名探鬼主播厂榛,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了击奶?” 一聲冷哼從身側(cè)響起辈双,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柜砾,沒想到半個(gè)月后湃望,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡局义,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年喜爷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萄唇。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡檩帐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出另萤,到底是詐尸還是另有隱情湃密,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布四敞,位于F島的核電站泛源,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏忿危。R本人自食惡果不足惜达箍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铺厨。 院中可真熱鬧缎玫,春花似錦、人聲如沸解滓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洼裤。三九已至邻辉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腮鞍,已是汗流浹背值骇。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缕减,地道東北人雷客。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像桥狡,于是被迫代替她去往敵國和親搅裙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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