linkedList-clone制造deep copy

有两个clone图和链表的题。基本的思路是,用一个hashmap来维护新旧对应的节点的映射关系。138那个题除了这种基本方法,还可以不用hashmap直接修改指针。

133. Clone Graph

在这里插入图片描述

给一个联通无向图的reference。node的定义:
class Node {
public int val;
public List neighbors;
} 求一个这个图的deep copy。

思路是:由旧图的reference point开始遍历旧图(数据结构给的是neighbor list,就用recursive DFS即可,代码结构简单),每到一个节点,先检查hashmap里是否已经有这个节点的cloned copy了(之前制造过了),有就直接用,没有就制造一个和当前值相同的cloned copy,并把<旧节点,新节点>的映射关系存入hashmap。

凡是记录,都是为了防止重复计算。这个hashmap,也是为了防止某个节点是好多个人的Neighbor,然后制造了很多个cloned copies,就很浪费了。

class Solution {
    Map<Node, Node> map = new HashMap<>();//<old,new>
    
    public Node cloneGraph(Node node) {
        return clone(node);
    }
    
    private Node clone(Node node) {//输入旧节点,返回对应的新节点
        if (node == null) {return node;}
        if (map.containsKey(node)) {
            return map.get(node);
        }
        Node newNode = new Node(node.val);
        map.put(node, newNode);
        for (Node neighbor : node.neighbors) {
            newNode.neighbors.add(clone(neighbor));
        }
        return newNode;
    }
}

138. Copy List with Random Pointer

在这里插入图片描述
这个题138和上面133的区别在于,133是graph,访问是乱七八糟的,有可能重复访问,而138主体是一个list,访问顺序很清楚,依次访问就可以依次制造出cloned copy,不需要hashmap。

需要hashmap的是random pointer。用hashmap记录<旧节点,新节点>映射关系,新节点在找random pointer的指向的时候,因为其对应的旧节点的random pointer的指向是已知的,于是,

  1. 通过hashmap先找到其对应的旧节点(这一步没法实现,因为是reverse查找hashmap,不支持
  2. 找旧节点random pointer的指向
  3. 指向的那个节点的对应的新节点,就是要求的“新节点random pointer的指向”。

第一步那个实现不了的怎么解决呢?把“制造新节点”和“连接random pointer”两个工作一起做。 这样,在制造好新节点的那个时刻,其对应旧节点的reference还在(因为新节点就是在遍历到旧节点的那个时刻制造出来的),就可以解决第一步“找旧节点”的问题了。

于是,list一共遍历两遍:

  • 开始的撸一遍旧list来先制造copy“主体”(即节点仅由next pointer连接)的过程,实际上并不连接next pointer,只是new出来一个新节点,放进hashmap里
  • 而“连接next pointer”的工作,被留着和“连接random pointer”一起当成后面第二轮撸。
class Solution {
    public Node copyRandomList(Node head) {
        Map<Node, Node> map = new HashMap<>(); //<oldnode, newnode>
        //create new nodes, put to map
        Node cur = head;
        while (cur != null) {
            map.put(cur, new Node(cur.val));
            cur = cur.next;
        }
        //connect next and random
        cur = head;
        while (cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);
    }
}

还可以不用hashmap,直接修改指针。
7->7->13->13->…->1->1->null

  1. 在原list的每个节点后面clone出一个新节点
  2. 依次给新节点的random pointer赋值
  3. 断开新旧混合的list,提取出deep copy的新链表(记得添加dummy)
class Solution {
    public Node copyRandomList(Node head) {
        Node iter = head, tempNext;
        //step 1: 在原list的每个节点后面clone出一个新节点
        while (iter != null) { //7->7->13->13->...->1->1->null
            tempNext = iter.next; //tempNext:13(1st)
            Node copy = new Node(iter.val);//copy:7(2nd)
            iter.next = copy;//iter:7(1st)
            copy.next = tempNext;
            iter = tempNext;
        }
        //step 2: 依次给新的节点的random pointer赋值
        iter = head;
        while (iter != null) {
            if (iter.random != null) {
                iter.next.random = iter.random.next;
            }
            //move pointer
            iter = iter.next.next;
        }
        //step 3: 断开新旧混合的list,提取出deep copy的新链表
        iter = head;
        Node dummy = new Node(-1);
        Node cur, pre = dummy;
        while (iter != null) {//7->7->13->13->...->1->1->null
            tempNext = iter.next.next;//tempNext:13
            //extract the copy
            cur = iter.next;//iter:7(1st),cur:7(2nd)
            pre.next = cur;
            pre = cur;
            //restore original list
            iter.next = tempNext;//7(1st)->13(1st)
            iter = tempNext;
        }
        return dummy.next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值