一、题目描述
【总结一句话:重新弄出一个完全一样链表】
给你一个长度为 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]]
示例 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
-104 <= Node.val <= 104
Node.random 为 null 或指向链表中的节点。
三、解题思路
3.1 建立旧结点-下标-新结点的映射关系
- 定义:ans 存放答案;映射 m 和 n 用来表示 旧结点到下标的映射 和 下标到新结点的映射;
- 第一次遍历:建立新结点,并建立 旧结点到下标的映射关系 和 下标到新结点的映射 ;
- 第二次遍历:根据 旧结点-下标-新结点 的映射关系来确定 random
3.2 合并+拆分
- 第一遍遍历:把链表的结点复制一份,并连接到对应节点的后面;【例如:原:a-b-c ,复制完 a-a‘-b-b’-c-c‘ 】
- 第二遍遍历:确定复制节点的随机指针,对于复制结点来说,其随机指针应该指向原本结点的下一个;【例如:假设 c 随机指向 a ,则 c’ 随机指向 a 的下一个结点,即 a‘ 】【注意空指针的处理,空指针没有下一个】
- 第三边遍历:拆分链表,将原本结点和复制结点拆分成两条链表。【注意最后一个结点的处理】
四、参考代码
4.1 建立旧结点-下标-新结点的映射关系
时间复杂度:
O
(
n
)
\Omicron(n)
O(n)
空间复杂度:
O
(
n
)
\Omicron(n)
O(n)
/*
// 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) {
if (head == NULL)
return NULL;
Node* ans = new Node(head->val);
unordered_map<Node*, int> m;
unordered_map<int, Node*> n;
int index = 0;
m[head] = index;
n[index] = ans;
index++;
for (Node *p = ans, *q = head->next; q != NULL; p = p->next, q = q->next) {
p->next = new Node(q->val);
m[q] = index;
n[index] = p->next;
index++;
}
for (Node *p = ans, *q = head; p != NULL; p = p->next, q = q->next) {
if (q->random == NULL) {
p->random = NULL;
} else {
p->random = n[m[q->random]];
}
}
return ans;
}
};
4.2 合并+拆分
时间复杂度:
O
(
n
)
\Omicron(n)
O(n)
空间复杂度:
O
(
n
)
\Omicron(n)
O(n) 【复制结点的空间,空间会比 4.1 小,因为不用存储 map】
/*
// 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) {
if(head==NULL) return NULL;
Node *ans=NULL;
for(Node *p=head;p!=NULL;p=p->next->next){
Node *t=new Node(p->val);
t->next=p->next;
p->next=t;
}
for(Node *p=head;p!=NULL;p=p->next->next){
p->next->random=(p->random==NULL)?NULL:p->random->next;
}
ans=head->next;
for(Node *p=head,*q=ans;q!=NULL;p=p->next,q=q->next){
p->next=q->next;
if(p->next!=NULL)
q->next=p->next->next;
else{
q->next=NULL;
break;
}
}
return ans;
}
};