深度拷贝带随即指针的链表

在这里插入图片描述

解法一(HashMap)

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public Node copyRandomList(Node head) {
        //一定记住健壮性
        if(head == null) {
            return null;
        }
        
        //通过hashmap来进行复制保存
        Map<Node, Node> map = new HashMap<Node, Node>();
        
        //用newHead去遍历
        Node newHead = head;
        
        while (newHead != null) {
            //如果HashMap没有当前节点,那么就进行复制,并且查找复制的节点是通过本来的节点映射得到
            if (!map.containsKey(newHead)) {
                Node copyNode = new Node(newHead.val);
                //映射两者
                map.put(newHead, copyNode);
            }
            
            //如果当前节点的Random不为空且该Random节点不在HashMap中,则复制Random
            if (newHead.random != null) {
                Node random = newHead.random;
                if (!map.containsKey(random)) {
                    Node copyRandom = new Node(random.val);
                    //建立映射
                    map.put(random, copyRandom);
                }
                
                //复制后的节点的random指针也该指向这个random节点
                map.get(newHead).random = map.get(random);
            }
            
            //下一个
            newHead = newHead.next;
        }

//上面这个while循环只是复制完了所有的节点,并且建立了节点与random节点之间的联系,但是链表的next还未建立联系
        newHead = head;
        while (newHead != null) {
            Node next = newHead.next;
            map.get(newHead).next = map.get(next);
            newHead = newHead.next;
        }
        return map.get(head);
    }
}

搭配图片理解算法过程
在这里插入图片描述
1指向3的指针即random指针

第一个while完成后,复制的链表就变成了这样
在这里插入图片描述
第二个while循环完成后就成功了
在这里插入图片描述

优点
使用HashMap进行复制和建立映射很方便。

缺点
由于要用HashMap来存储映射关系,所以空间消耗更多了,空间复杂度为O(n),

如果我们有另外一种方式来映射,就可以省去HashMap这种空间消耗了

解法二

图片理解
在这里插入图片描述
之前我们使用键值在HashMap中来获取复制的节点,现在我们就用原节点的next域来获取复制的节点,这种方式不存在映射空间的消耗

public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }
        //复制原节点
        copy(head);
        //并建立random节点的联系
        copyRandom(head);
        //上面两步完成后就是上图的效果了,上图差了一个random线。

        //拆开后返回
        return split(head);
    }
    
    //建立图示想要的next即为复制节点的链表
    public void copy(Node head) {
        Node node = head;
        while(node != null) {
            Node copy = new Node(node.val);
            copy.next = node.next;
            node.next = copy;
            node = copy.next;
        }
    }
    
    //建立Random的联系
    public void copyRandom(Node head) {
        Node node = head;
        while(node != null && node.next != null) {
            if (node.random != null) {
            //next节点即为复制后的节点,例如1‘,让它的random去指向复制后的random
                node.next.random = node.random.next;
            }
            //一次性跳两个,因为不需要去遍历复制的节点 
            node = node.next.next;
        }
    }
    
    //拆开图示链表,分开为两个一样的链表
    public Node split(Node head) {
        Node result = head.next;
        Node move = head.next;
        while(head != null && head.next != null) {
        //原节点不指向复制节点了,而指向本身该指向的下一个节点
            head.next = head.next.next;
            head = head.next;
            if (move != null && move.next != null) {
            //同上道理
                move.next = move.next.next;
                move = move.next;
            }
        }
        return result;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值