149 lines
3.8 KiB
JavaScript
149 lines
3.8 KiB
JavaScript
/**
|
||
* https://leetcode.cn/problems/copy-list-with-random-pointer/?envType=study-plan-v2&envId=top-interview-150
|
||
* // Definition for a _Node.
|
||
* function _Node(val, next, random) {
|
||
* this.val = val;
|
||
* this.next = next;
|
||
* this.random = random;
|
||
* };
|
||
*/
|
||
|
||
/**
|
||
* @param {_Node} head
|
||
* @return {_Node}
|
||
*/
|
||
const copyRandomList = function (head) {
|
||
|
||
};
|
||
|
||
// Definition for a _Node.
|
||
// eslint-disable-next-line no-underscore-dangle
|
||
function _Node(val, next, random) {
|
||
this.val = val;
|
||
this.next = next;
|
||
this.random = random;
|
||
}
|
||
|
||
/*
|
||
遍历整个链表,创建每一个节点的克隆节点,并且使用map将它们直接联系起来,原节点作为key,新节点作为value,
|
||
遍历完毕之后,再遍历一一遍原链表,根据random_index和map来为可能列表添加random_index
|
||
*/
|
||
function f1(head) {
|
||
const map = new Map(); // 储存原链表和克隆链表直接的关系
|
||
const dummyHead = new _Node(); // 哑节点,用于构建克隆链表
|
||
let curClone = dummyHead;
|
||
let cur = head;
|
||
|
||
while (cur) {
|
||
// 创建克隆节点
|
||
curClone.next = new _Node(cur.val);
|
||
curClone = curClone.next;
|
||
// 将原节点和克隆节点映射
|
||
map.set(cur, curClone);
|
||
cur = cur.next;
|
||
}
|
||
|
||
// 遍历原节点,根据原节点的信息为克隆节点添加random指针
|
||
cur = head;
|
||
curClone = dummyHead.next;
|
||
while (cur) {
|
||
if (cur.random) {
|
||
curClone.random = map.get(cur.random);
|
||
}
|
||
cur = cur.next;
|
||
curClone = curClone.next;
|
||
}
|
||
return dummyHead.next;
|
||
}
|
||
|
||
/*
|
||
f1 的优化版本,首先创建克隆节点和映射,之后再拼接克隆链表
|
||
*/
|
||
function f2(head) {
|
||
if (!head) return null;
|
||
|
||
const map = new Map(); // 储存原节点 => 克隆节点的映射
|
||
let cur = head;
|
||
|
||
// 第一次遍历:创建所有新节点,并放入 map 中
|
||
while (cur) {
|
||
map.set(cur, new _Node(cur.val));
|
||
cur = cur.next;
|
||
}
|
||
|
||
cur = head;
|
||
|
||
// 第二次遍历:设置新节点的 next 和 random 指针
|
||
while (cur) {
|
||
const cloneNode = map.get(cur);
|
||
cloneNode.next = map.get(cur.next) || null;
|
||
cloneNode.random = map.get(cur.random) || null;
|
||
cur = cur.next;
|
||
}
|
||
|
||
return map.get(head);
|
||
}
|
||
|
||
/*
|
||
直接再原节点中插入克隆节点,那么原节点和克隆节点就存在了引用关系,之后根据引用关系来设置random,最后
|
||
分离原链表和克隆链表即可
|
||
*/
|
||
|
||
function f3(head) {
|
||
if (!head) return null;
|
||
|
||
// 创建克隆节点,并且把克隆节点放在原节点后面
|
||
let cur = head;
|
||
while (cur) {
|
||
// 将原节点之后的所有节点移动到克隆节点的后面,再将克隆节点作为原节点的next
|
||
const clone = new _Node(cur.val);
|
||
clone.next = cur.next;
|
||
cur.next = clone;
|
||
cur = clone.next; // 遍历下一个原节点
|
||
}
|
||
|
||
// 更具原节点的random来设置克隆节点的random
|
||
|
||
cur = head;
|
||
while (cur) {
|
||
if (cur.random) {
|
||
cur.next.random = cur.random.next;
|
||
}
|
||
cur = cur.next.next; // 下一个原节点
|
||
}
|
||
|
||
// 分离节点
|
||
cur = head;
|
||
const cloneHead = head.next;
|
||
while (cur) {
|
||
const clone = cur.next;
|
||
cur.next = clone.next; // 原节点指向原本下一个节点
|
||
if (clone.next) {
|
||
clone.next = clone.next.next; // 克隆节点指向克隆节点的下一个节点
|
||
}
|
||
cur = cur.next;
|
||
}
|
||
return cloneHead;
|
||
}
|
||
|
||
/*
|
||
回溯加哈希表
|
||
*/
|
||
|
||
function f4(head, cacheMap = new Map()) {
|
||
if (!head) return null;
|
||
|
||
// 如果没有这个节点的克隆映射
|
||
if (!cacheMap.has(head)) {
|
||
const clone = new _Node(head.val);
|
||
cacheMap.set(head, clone);
|
||
// 克隆节点的下一个节点为当前节点的下一个节点的克隆节点,递归调用即可
|
||
clone.next = f4(head.next, cacheMap);
|
||
// random同理
|
||
clone.random = f4(head.random, cacheMap);
|
||
}
|
||
|
||
// 如果有克隆节点,直接返回
|
||
return cacheMap.get(head);
|
||
}
|