要求
一个长度为 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 作为传入参数。
思路
题目描述如下图
那我们可以先不管混乱的random指针
即下图
既然题目要求是深拷贝,那我们可以在原节点后面都加上一个“拷贝节点”(根据next指针排序)
即下图
此时,需要注意节点的random指向,因为我们是拷贝原节点的random,所以random目前指向原节点,需要让拷贝节点的random指向拷贝节点才行
即下图
需要变成下图
代码表现
copy.random = copy.random.next
然后再把拷贝节点抽离出来,return拷贝节点的头即可
代码
var copyRandomList = function (head) {
// 当传入的head为空,直接return出去
if (!head) return null
// 创建两个指针,pre指向head
let pre = head,
copy;
// 加克隆节点,克隆原节点的所有数据,并且排在原节点后面,然后改变pre的指向
while (pre) {
copy = new Node(pre.val, pre.next, pre.random);
pre.next = copy;
pre = pre.next.next;
}
copy = head.next;
// 改变克隆节点的random指向,然后copy指针继续寻找下一个克隆的节点,当找到最后一个,copy指针指向null(进入else)
while (copy) {
// 这是另一种写法
// pre.random && (pre.random = pre.random.next);
// (pre = pre.next) && (pre = pre.next);
if (copy.random) {
copy.random = copy.random.next;
}
if (copy.next) {
copy = copy.next.next;
} else {
copy = copy.next;
}
}
// 两指针都指向head.next(克隆节点),一个指针用于while循环的指向,一个指针用于return
pre = copy = head.next;
// 当克隆节点的下一节点(原节点/null)还有值(还未循环到最后的null)时
// 抽离克隆节点成一个链表
while (pre.next) {
// head是原节点,原节点的指针指向下一个原节点
// 注意,此处head不只代表传入的链表的第一个节点
head.next = head.next.next;
// pre是克隆节点,克隆节点指向下一个克隆节点
pre.next = pre.next.next;
// head指针指向下一个原节点
head = head.next;
// pre指针指向下一个克隆节点
pre = pre.next;
}
// 断开最后一个原节点与克隆节点的next指向
head.next = null;
// 此时copy还指向第一个克隆节点,返回copy即可
return copy;
};