Leetcode笔记----剑指offer35.复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

显然题目想实现链表的深拷贝,和传统的链表复制不同处在于,传统的简单链表只有val和next域,只要一边遍历一边新建节点连接即可。但random指针指向的节点位置不固定,可能在很后面遍历的时候该节点还未创建,所以需要一些新的处理。
略加思考之后我写出了一个笨方法:next指针的复制照常,同时用一个int数组记录每个节点的random域位置,最后再遍历一遍新链表将random域填上,如下所示。

public Node copyRandomList(Node head) {
        Node dummy = new Node(-1);
        Node dummyd = new Node(-1);
        dummyd.next = dummy;
        Node p = head;
        int length = 0;
        while(p!=null){
            length++;
            dummy.next = new Node(p.val);
            p = p.next;
            dummy = dummy.next;
        }
        int randomloc[] = new int[length+1];
        int loc = 0;
        p = head;
        dummy = dummyd.next.next;
        while(p!=null){
           if(p.random==null){randomloc[loc] = -1;}
           if(p.random == p){randomloc[loc] = -2;}
           Node start = head;
           int realloc = 0;
           while(start!=p.random){
               start = start.next;
               realloc++;
           }    
           randomloc[loc] = realloc;
           loc++;
           p = p.next;
        }
        p = head;
        loc = 0;
        while(dummy!=null){
            if(randomloc[loc]==-1){
                dummy.random = null;   
            }
            else if(randomloc[loc]==-2){
                dummy.random = dummy;     
            }
            else{
                Node start = dummyd.next.next;
                int index = 0;
                while(index!=randomloc[loc]){
                    start = start.next;
                    index++;
                }
                dummy.random = start;
            }
            dummy = dummy.next;
            loc++;
        }
        return dummyd.next.next;
    }

可想而知,该方法时间复杂度非常高,毕竟涉及到O(N²)级别的遍历。在阅读大佬题解后简单方法看得我五体投地:在遍历原链表的同时直接把新节点都连接在原链表上,每个旧节点后连一个val值相同的新节点。第一次遍历后得到一个扩大二倍的链表,再来一次遍历把每个新节点的random域补全:每个新节点的random域肯定是前一个节点(旧节点)的random域的next域(新的random)。最终将新旧链表拆分,返回新链表即可。思路实在厉害

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node cur = head;
        // 1. 复制各节点,并构建拼接链表
        while(cur != null) {
            Node tmp = new Node(cur.val);
            tmp.next = cur.next;
            cur.next = tmp;
            cur = tmp.next;
        }
        // 2. 构建各新节点的 random 指向
        cur = head;
        while(cur != null) {
            if(cur.random != null)
                cur.next.random = cur.random.next;
            cur = cur.next.next;
        }
        // 3. 拆分两链表
        cur = head.next;
        Node pre = head, res = head.next;
        while(cur.next != null) {
            pre.next = pre.next.next;
            cur.next = cur.next.next;
            pre = pre.next;
            cur = cur.next;
        }
        pre.next = null; // 单独处理原链表尾节点
        return res;      // 返回新链表头节点
    }
}

作者:jyd
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/jian-zhi-offer-35-fu-za-lian-biao-de-fu-zhi-ha-xi-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值