【Leetcode】138. Copy List with Random Pointer

题目地址:

https://leetcode.com/problems/copy-list-with-random-pointer/

给定一个链表,每个node不但指向下一个node,还指向另一个random node。要求deep copy一份这个链表。

法1:DFS。同copy二叉树是类似的,这里可以采用递归的办法。但与二叉树不同的是,二叉树没有环,而这个链表的random有可能会指向之前的node,所以这里需要用一个哈希表记录一下某个node有没有被copy过。如果有的话,直接返回那个之前copy的就行了。否则就new一个新的。代码如下:

import java.util.HashMap;
import java.util.Map;

public class Solution {
    public Node copyRandomList(Node head) {
    	// 记录已经被copy过的node和它们对应的node,
    	// key是原链表的node,value是深拷贝出来的对应的node
        Map<Node, Node> map = new HashMap<>();
        // null直接copy为null
        map.put(null, null);
        return dfs(head, map);
    }
    // 返回深拷贝出来的与参数node相对应的node
    private Node dfs(Node node, Map<Node, Node> map) {
    	// 如果该node已经被拷贝过,那就直接get出来返回
        if (map.containsKey(node)) {
            return map.get(node);
        }
        // 否则说明没拷贝过,那就先拷贝一个出来
        map.put(node, new Node(node.val));
        // 将其next和random也拷贝出来,接上去
        map.get(node).next = dfs(node.next, map);
        map.get(node).random = dfs(node.random, map);
        // 返回这个新拷贝出来的node
        return map.get(node);
    }
}

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

时间 O ( n ) O(n) O(n),空间 O ( n ) O(n) O(n)

法2:BFS。模仿BFS一个图的方法来做,也是要用一个哈希表记录已经copy过的node和其对应的node,然后用一个队列来做BFS。遇到未copy过的node就new出来接上去,否则直接接上已经copy过的那个对应的node。代码如下:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

public class Solution {
    public Node copyRandomList(Node head) {
    	// 判空
        if (head == null) {
            return null;
        }
        // 记录已经copy过的node及其对应的node。含义同上
        Map<Node, Node> map = new HashMap<>();
        // 先把head拷贝一份
        map.put(head, new Node(head.val));
        // 再开一个队列把head放进去,以便于BFS
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            // 如果cur的next不为null且cur的next没被copy过的话,就new一个出来,建立map中的关联,并入队
            if (cur.next != null && !map.containsKey(cur.next)) {
                map.put(cur.next, new Node(cur.next.val));
                queue.offer(cur.next);
            }
            // 把cur对应的node的next给连上去
            map.get(cur).next = map.get(cur.next);
            // 与上面的next类似,copy出random
            if (cur.random != null && !map.containsKey(cur.random)) {
                map.put(cur.random, new Node(cur.random.val));
                queue.offer(cur.random);
            }
            map.get(cur).random = map.get(cur.random);
        }
        
        return map.get(head);
    }
}

时间复杂度 O ( n ) O(n) O(n),空间 O ( n ) O(n) O(n)

法3:拷贝后连在原链表内,然后再分离出来。遍历原链表,每次遍历到一个节点的时候,先把当前链表节点复制出来插到后面,遍历完后新节点全new出来了。然后把random的边复制出来,接着再把new出来的节点分离出来即可。代码如下:

public class Solution {
    public Node copyRandomList(Node head) {
        Node cur = head;
        // 把节点new出来,插进链表里
        while (cur != null) {
            Node node = new Node(cur.val);
            node.next = cur.next;
            cur.next = node;
            cur = cur.next.next;
        }
        
        // 把random的那条边也copy出来
        cur = head;
        while (cur != null) {
        	// 注意这里要特判一下random不为空
            if (cur.random != null) {
                cur.next.random = cur.random.next;
            }
            cur = cur.next.next;
        }
        
        Node dummy = new Node(0), prev = dummy;
        cur = head;
        // 把new出来的节点插在dummy后面,恢复原链表
        while (cur != null) {
            prev.next = cur.next;
            cur.next = cur.next.next;
            cur = cur.next;
            prev = prev.next;
        }
        
        return dummy.next;
    }
}

时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值