LeetCode——138. Copy List with Random Pointer

来源:互联网 发布:成都机场附近住宿 知乎 编辑:程序博客网 时间:2024/06/01 08:23

问题描述:

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.Return a deep copy of the list.

  这道题大致的意思就是,一个链表,它每一个节点除了一个next引用以外,还有一个random引用,它指向链表上的任意一个点,或者是null。我们要做的就是深拷贝这个链表——就是重新申请内存建一个一模一样的链表。
  对于这道题,我刚开始的想法是先复制一个新的链表,然后通过在原链表中计算当前节点到random指向的节点的距离,然后在新链表的节点上根据距离操作一次,发现这个方法好笨。后来看了别人的博客,头脑才开窍了。
  其实你要想在新链表中找到原链表节点的random引用指向的节点对应的节点,那我们可以在复制链表的时候,将原链表的节点与新链表对应的节点相连接,那么当你在访问原链表的节点时,就可以高效地访问到在新链表上对应的节点,random就可以高效的复制。
  既然要在原链表和新链表的节点上建立连接,那么其中的一种方法就是使用hashmap,用原链表的节点作键,新链表上对应的节点作值。那么我们在访问原链表上的节点时,就可以直接在新链表上找到对应的节点,再进行赋值,这种方法明显快多了,也方便多了。下面是代码:

    public RandomListNode copyRandomList(RandomListNode head) {        if(head == null)            return null;        RandomListNode newHead = new RandomListNode(head.label);        //用hashmap来将旧节点和新节点建立联系        Map<RandomListNode, RandomListNode> tempMap = new HashMap<>();        tempMap.put(head, newHead);        RandomListNode cur = newHead;        //先复制新的链表        for(RandomListNode p = head.next; p != null; p = p.next) {            cur.next = new RandomListNode(p.label);            cur = cur.next;            tempMap.put(p, cur);        }        cur.next = null;        cur = newHead;        //根据旧节点的random,在hashmap中寻找新节点在新链表上对应的ransom,实现高效查找        for(RandomListNode p = head; p != null; p = p.next) {            cur.random = tempMap.get(p.random);            cur = cur.next;        }        return newHead;    }

  这种方法很好理解,也很好想, 就是需要o(n)的空间复杂度。还有一种方法可以优化,使得空间复杂度变为常数级。这种方法的核心想法还是将原链表上的节点与新链表上对应的节点建立连接,只不过它是直接将新节点插在对应的旧节点的后面,这个新节点指向原来对应旧节点的下一个旧节点。可以看下面这张图,你们就很容易理解了:
  复制完新链表后,将原链表和新链表合体,变成这种形式
  
  再复制完新链表后,将原链表和新链表合体,变成上图的这种形式,不也就实现了原节点和新节点之间的连接关系吗?然后将新链表上的每个节点的random引用都解决了之后,再将它们分开,就大功告成了。下面是具体代码:

    public RandomListNode copyRandomList(RandomListNode head) {        if(head == null)            return null;        RandomListNode newHead = new RandomListNode(head.label);        RandomListNode tempNode = head.next;        head.next = newHead;        newHead.next = tempNode;        RandomListNode oldP = newHead.next;        RandomListNode newP = newHead;        //第一遍遍历,将新链表的每个节点插到原链表的两个节点之间,相当于原链表的每一个节点会连接到新链表对应的节点        while(oldP != null) {            tempNode = oldP.next;            oldP.next = new RandomListNode(oldP.label);            oldP.next.next = tempNode;            newP = oldP.next;            oldP = oldP.next.next;        }        //第二遍遍历,根据上面设置的对应关系,访问原链表节点上的random,然后设置新链表上对应节点的random        oldP = head;        newP = newHead;        while(oldP != null) {            //如果原节点random指向null,新节点random直接指向null            if(oldP.random == null)                newP.random = null;            //否则通过原节点的random找到在新链表中该节点的random需要连接的对应的节点,然后连接            else {                newP.random = oldP.random.next;            }              oldP = oldP.next.next;            if(oldP != null)                newP = newP.next.next;        }        //第三遍遍历,将新链表拆出来        oldP = head;        newP = newHead;        while(newP != null) {            oldP.next = newP.next;            oldP = oldP.next;            if(newP.next != null)                newP.next = newP.next.next;            newP = newP.next;        }        return newHead;    }

  
  这道题总的来说,还是不太难的,重点是,你要想到将原链表上的节点与新链表上的节点连接起来,通过访问原链表上的节点就可以访问新链表上对应的节点,那么这道题就可以轻松解决了!
  谢谢大家观看我的博客。如果有不明白的地方,或者是文中有错误的地方,欢迎指出,谢谢!如果大家喜欢我的博客,也可以给我点点赞。你们的点赞就是我的动力!

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 魅蓝e被锁机了怎么办 魅蓝3s卡顿怎么办 魅族note5玩王者荣耀卡怎么办 魅族手机内存不够怎么办 魅族手机音量小怎么办 魅族mx5指纹解锁失灵怎么办 魅族手机费电快怎么办 魅族mx4pro玩王者荣耀卡怎么办 魅蓝5s玩游戏卡怎么办 魅蓝s6玩游戏卡怎么办 OPPO王者荣耀对局闪退怎么办 魅族手机太慢怎么办 魅蓝5信号不好怎么办 魅蓝数据网速慢怎么办 魅族联通网速慢怎么办 魅族手机wifi信号弱怎么办 魅蓝e2信号差怎么办 魅蓝e2gps信号弱怎么办 魅族网络信号差怎么办 魅族手机gps信号弱怎么办 魅族手机突然没有信号怎么办 魅族手机流量信号不好怎么办 魅族手机wifi信号差怎么办 魅族5s信号不好怎么办 魅族mx5的双击不亮屏怎么办 魅族mx5返回键失灵怎么办 电信苹果3g网速慢怎么办 魅蓝6开不了机怎么办 手机应用被锁了怎么办 魅族电池不耐用怎么办 魅族mx6现在很卡怎么办 魅族e2手机屏幕背景黑色怎么办 魅族x6手机锁了怎么办 360n5返回键失灵怎么办 360n5返回键不好用怎么办 魅族手机锁屏怎么办 魅族手机锁住了怎么办 手机己锁定怎么办魅族 魅蓝u10触屏没反应怎么办 魅蓝e2手机锁定怎么办 苹果手机声音键坏了怎么办