LeetCode138 复制带随机指针的链表 & 剑指Offer 35 复杂链表的复制
题目
解题
解题一:回溯 + 哈希表
注意计入哈希表的操作一定要在寻找 next 和 random 指向的节点之前,否则如果存在环就会 exceeds maximum stack size。 这是因为哈希表内存储的是节点的地址,分配的地址是不会变的,后续如果该节点的值或 random / next 指向的节点发生了变化,我们通过该地址获取的还是最新的节点(可以理解成:跑得了和尚跑不了庙?)。如果没有先存地址,那可能出现节点 A 调用函数去寻找节点 B,节点 B 又调用函数去寻找节点 A,没完没了。
示例2是有环的,如果理解不了上面的话,可以走一遍该示例。
// javascript
var copyRandomList = function(head, cacheNode = new Map()) {
if (head === null) return null;
if (cacheNode.has(head) === false) {
const headNew = new Node(head.val);
cacheNode.set(head, headNew); // 先计入哈希表
headNew.next = copyRandomList(head.next, cacheNode);
headNew.random = copyRandomList(head.random, cacheNode);
}
return cacheNode.get(head);
};
解题二:迭代 + 节点拆分
强烈建议拿着代码过一遍,要注意的细节注释里有标注。
// javascript
var copyRandomList = function(head) {
if (head === null) return null;
// 因为复制的节点已经插入链表,所以是 node = node.next.next
for (let node = head; node !== null; node = node.next.next) {
const nodeNew = new Node(node.val, node.next, null);
node.next = nodeNew;
}
// 复制 random 指针
for (let node = head; node !== null; node = node.next.next) {
const nodeNew = node.next;
nodeNew.random = (node.random !== null) ? node.random.next : null;
}
// 记录复制链表的头节点
const headNew = head.next;
// 因为在分割两个链表,所以是 node = node.next
// 如果 node !== null, 后面必定有 node.next (nodeNew) !== null
// 但是对于最后一个 node 来说,nodeNew.next 是 null,所以要判断哦
for (let node = head; node !== null; node = node.next) {
const nodeNew = node.next;
node.next = node.next.next;
nodeNew.next = (nodeNew.next !== null) ? nodeNew.next.next : null;
}
return headNew;
};