【LeetCode刷题笔记Java】138.复制带随机指针的链表

  • 题目:给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
    构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
    例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
    返回复制链表的头节点。
    用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
    val:一个表示 Node.val 的整数。
    random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
    你的代码 只 接受原链表的头节点 head 作为传入参数。

示例:输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

  • 哈希表保存新老节点映射,时间复杂度O(N),空间复杂度O(N)
    public Node copyRandomList(Node head){
        if (head == null)
            return null;
//        map储存key为老节点,value为新节点的映射
        HashMap<Node, Node> map = new HashMap<>();
//        辅助节点pre帮助创建新链表
        Node pre = new Node(-1);
        Node tail = pre;
//        从头遍历一遍链表
        while (head != null){
//            如果说head节点在map已经存在,说明之前有某个节点的random指向它提前把它创建出来了,
//            那么新节点的next直接指向它就可以
            if (map.containsKey(head)){
                tail.next = map.get(head);
                tail = tail.next;
//                如果不存在,就创建一个新节点把next指向他,并且把新节点和旧节点head的映射存入map
            }else {
                tail.next = new Node(head.val);
                tail = tail.next;
                map.put(head, tail);
            }
//            如果head的random指向null,不用考虑其他情况,新节点的random也指向random
            if (head.random == null){
                tail.random = null;
            }else {
//                不指向null,那要考虑random指向的节点此时有没有被创建出来
//                如果已经被创建,新random直接指过去
                if (map.containsKey(head.random)) {
                    tail.random = map.get(head.random);
                } else {
//                    如果没创建,创建一个然后把random指过去
                    tail.random = new Node(head.random.val);
                    map.put(head.random, tail.random);
                }
            }
            head = head.next;
        }
        return pre.next;
    }
  • 节点穿插,利用新旧节点之间的位置关系代替哈希表,完成random节点的寻找。
    public Node copyRandomList(Node head) {
        if (head == null)
            return null;
        Node cur = head;
        Node next = null;
//        第一次遍历创建出新节点并穿插进旧链表中
        while (cur != null){
            next = cur.next;
            cur.next = new Node(cur.val);
            cur.next.next = next;
            cur = next;
        }

        cur = head;
        Node curCopy = null;
//        第二次循环要把新节点的random指向旧节点对应random的next位置(就是应该指向的地方)
        while (cur != null){
            next = cur.next.next;
            curCopy = cur.next;
            curCopy.random = cur.random != null ? cur.random.next : null;
            cur = next;
        }

        Node res = head.next;
        cur = head;
//        第三次遍历把新节点剥离出来
        while (cur != null){
            next = cur.next.next;
            curCopy = cur.next;
            cur.next = next;
            curCopy.next = next != null ? next.next : null;
            cur = next;
        }
        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值