前言
如何复制一个链表,并且这个链表中的节点还带有随机指针,最后复制的链表还和原链表没有指针的指向关系?看这里,只需3步即可完成!
题目描述(题目略长懂得直接看思路)
复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。 random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。 你的代码 只 接受原链表的头节点 head 作为传入参数。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
解题思路
- 利用题目Node函数复制带有随机指针的节点追加到每个原节点后(得到节点与原节点有相同的指向)
- 纠正随机指针的指向问题
- 就复制节点拆出来并且保持原有链表
开始解题
/**
* // Definition for a Node.
* function Node(val, next, random) {
* this.val = val;
* this.next = next;
* this.random = random;
* };
*/
/**
* @param {Node} head
* @return {Node}
*/
var copyRandomList = function(head) {
if(!head) return null;
let cur = head;
let cNode = null; // while 循环外初始化复制节点,避免每次都声明
while(cur) {
let next = cur.next; // 保存cur.next不丢失
cNode = new Node(cur.val,next,cur.random);// 复制原有节点
cur.next = cNode; // cur连接复制的cNode节点,为什么没写cNode.next = cur.next? 因为在Node方法里已经做了这一步
cur = next;
} // 每个复制节点都会跟在原节点后面
cur = head.next; // 让cur指向head的下一个节点,也就是复制节点,因为我们用从复制节点开始纠正随机指针
while(cur) {
cur.random && (cur.random = cur.random.next); // 随机指针指向的节点后也是有复制节点,如果cur有随机指针,我们就让cur.random指向原节点随机指针指向节点的复制节点即可
(cur = cur.next) && (cur = cur.next); // 每间隔一位才是复制节点
}
let temp = head.next; // 保存一下head.next作为我们复制链表的头节点返回
cur = head.next; // 操作cur指针拆出我们的复制链表
while(cur.next) { // 当cur.next 为null也就是已经遍历到最后一个复制节点了
let next = head.next.next;
let temp = cur.next.next;
head.next = head.next.next; // 让head连接head的下下个节点
cur.next = cur.next.next; // 让cur连接cur的下下个节点,cur与head间隔相连,拆成两条链表
cur = temp;
head = next;
}
head.next = null; // 复制节点是最后一个节点不用指向null,head为复制节点的前一个节点需要断开去指向null,拆解完毕
return temp;
};