138. 复制带随机指针的链表

876 阅读2分钟

题目描述

leetcode-cn.com/problems/co…

分析

输入:链表头节点 head 输出:神拷贝之后的链表头节点

解题思路

看题目描述可以知道,给我们的链表的每一个节点,多了一个 random 属性,它指向什么,是不一定的,只知道是某个节点,所以我们在深拷贝的时候,要考虑到 random 节点还没有被创建出来的情况,所以是不是可以用递归的思想,如果某个节点被创建了,就直接返回节点,没有创建我们就去创建。

在这个过程中,我们需要一个哈希表来存储创建的节点。

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function (head, map = new Map()) {
  if (head === null) return null;

  if (!map.has(head)) {
    map.set(head, {
      val: head.val,
    });

    // take care that we should firstly create one node before we go deeper, or there never gonna be one node created
    Object.assign(map.get(head), {
      next: copyRandomList(head.next, map),
      random: copyRandomList(head.random, map),
    });
  }

  return map.get(head);
};

我们先给参数加一个 map,这个参数会在每次递归的时候使用。

首先,我们会从头地去对所有节点进行深拷贝,在这个过程中如果发现某个节点已经被创建了,就直接返回。

那一定是先从 head 开始,首先在 map 里创建 head

这里要注意 ⚠️ 为什么使用 assign

如果我们在 map 里直接的 set {val, next, random} 这么一个对象,我们可以想象到的是

由于我们是一直在进行递归,所以一个节点都不会被创建,一直地在执行函数,所以直接就报错了。

正确的做法是先创建一个没有 next, random 的节点, setmap,在进行递归操作。

在拷贝完之后,直接返回拷贝的 head 就可以了。

代码

```javascript
/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function (head, map = new Map()) {
  if (head === null) return null;

  if (!map.has(head)) {
    map.set(head, {
      val: head.val,
    });

    // take care that we should firstly create one node before we go deeper, or there never gonna be one node created
    Object.assign(map.get(head), {
      next: copyRandomList(head.next, map),
      random: copyRandomList(head.random, map),
    });
  }

  return map.get(head);
};

复杂度

时间:O(N), 最多遍历了两遍链表 空间:O(N), 用了一个哈希表,存储节点