难度: m i d d l e \color{orange}{middle} middle
题目描述
给你一个长度为 n n n 的链表,每个节点包含一个额外增加的随机指针 r a n d o m random random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝 。 深拷贝应该正好由 n n n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 n e x t next next 指针和 r a n d o m random random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。 复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X X X 和 Y Y Y 两个节点,其中 X . r a n d o m − − > Y X.random --> Y X.random−−>Y 。那么在复制链表中对应的两个节点 x x x 和 y y y ,同样有 x . r a n d o m − − > y x.random --> y x.random−−>y 。
返回复制链表的头节点。
用一个由 n n n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [ v a l , r a n d o m i n d e x ] [val, random_index] [val,randomindex] 表示:
- v a l val val:一个表示 N o d e . v a l Node.val Node.val 的整数。
- r a n d o m i n d e x random_index randomindex:随机指针指向的节点索引(范围从 0 0 0 到 n − 1 n-1 n−1);如果不指向任何节点,则为 n u l l null null 。
你的代码 只 接受原链表的头节点 h e a d head head 作为传入参数。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
提示:
- 0 < = n < = 1000 0 <= n <= 1000 0<=n<=1000
- − 1 0 4 < = N o d e . v a l < = 1 0 4 -10^{4} <= Node.val <= 10^{4} −104<=Node.val<=104
- N o d e . r a n d o m Node.random Node.random 为 n u l l null null 或指向链表中的节点。
算法
(哈希表) O ( n ) O(n) O(n)
- 给链表中每一个节点复制一个新的节点,节点的位置就在当前节点的 next 指针下。
- 把原链表中的 random 指针关系复制到 新的链表上。
- 拆分链表,把复制的链表拆分成新的链表,就是答案。
C++ 代码
/*
// 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 (auto p = head; p; p = p->next->next) {
auto q = new Node(p->val);
q->next = p->next;
p->next = q;
}
//复制random
for (auto p = head; p; p = p->next->next) {
if (p->random)
p->next->random = p->random->next;
}
auto dummy = new Node(-1), cur = dummy;
//拆分
for (auto p = head; p; p = p->next) {
auto q = p->next;
cur = cur->next = q;
p->next = q->next;
}
return dummy->next;
}
};