题目描述
分析
输入:链表头节点 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 的节点, set 进 map,在进行递归操作。
在拷贝完之后,直接返回拷贝的 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), 用了一个哈希表,存储节点