138. 复制带随机指针的链表(leetcode)
难度:中等
给你一个长度为 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 作为传入参数。
来源:力扣(LeetCode) 链接:力扣
思路:本题的难点是 每个节点复刻随机指针(可以指向链表中任何节点或空节点)不一定会指向下一个节点。
那我们该怎么去复刻随机指针呢?
我们可以复制每个节点的值,并把它们接到对应的节点后。
如图
核心操作:p->next->random = p->random->next
总结:
运用迭代法:
第一次迭代:复刻每个节点的值,并接到节点后
第二次迭代:对random指针赋值
第三次迭代:拆分链表,运用哑节点技巧(避免对头结点进行特判)。
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
for(Node *p=head;p;p=p->next->next) {
Node *q = new Node(p->val);// 创建一个值为val的新节点
q->next = p->next;
p->next = q; // 接到p节点的后面
}//第一次迭代
for (Node *p=head;p;p=p->next->next) {
if(p->random) //节点判空
p->next->random = p->random->next;
}//第二次迭代
Node *dummy=new Node(-1);
Node *cur = dummy;
for(Node *p=head;p;p=p->next) {
Node *q = p->next;
cur->next = q;
cur = cur->next;//第35行和36行可合并为 cur = cur->next = q;
p->next=q->next;//难想点
}
return dummy->next;
}
};