algorighm/top-interview-leetcode150/link/138随机链表的复制.js

149 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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);
}