题目描述
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
- val:一个表示 Node.val 的整数。
- random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
示例:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
题目链接: https://leetcode-cn.com/problems/copy-list-with-random-pointer/
思路1
分 3 步:
第 1 步,复制链表中的每个节点并放在该节点的后面
我们发现:
- 原节点 1 的随机指针指向原节点 3,新节点 1 的随机指针指向的是原节点 3 的next;
- 原节点 3 的随机指针指向原节点 2,新节点 3 的随机指针指向的是原节点 2 的next;
也就是也就是,原节点 i 的随机指针(如果有的话),指向的是原节点 j,那么新节点 i 的随机指针,指向的是原节点 j 的 next;
所以,第 2 步就是遍历链表,假设当前结点为 cur,则 cur->next->random = cur->random->next(如果 cur->random!=nullptr);
第 3 步就是把 2 个链表分开
这一步就是奇偶链表的做法。
/*
// 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==nullptr) return head;
/*第1步:将复制的节点放在当前节点后面*/
Node* cur = head;
while(cur!=nullptr){
Node* copy = new Node(cur->val);
copy->next = cur->next;
cur->next = copy;
cur = cur->next->next;
}
/*第2步:设置复制的节点的random指针*/
cur = head;
while(cur!=nullptr){
if(cur->random!=nullptr) cur->next->random = cur->random->next; // 注意条件
cur = cur->next->next;
}
/*第3步:分类两个链表*/
Node* dummy = new Node(0);
Node* cur1 = head;
Node* cur2 = dummy;
while(cur1 && cur2){
Node* next1 = cur1->next;
cur2->next = next1;
cur1->next = next1->next;
cur1 = cur1->next;
cur2 = cur2->next;
}
return dummy->next;
}
};
或者这样写,也是 3 个步骤,第 3 步的实现有点不同:
/*
// 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 head;
Node* cur = head;
while(cur!=NULL){
Node* copy = new Node(cur->val);
Node* next = cur->next;
cur->next = copy;
copy->next = next;
cur = next;
}
cur = head;
while(cur!=NULL){
if(cur->random) cur->next->random = cur->random->next;
cur = cur->next->next;
}
Node* dummy = new Node(0);
cur = head;
Node* newCur = dummy;
while(cur!=NULL){
newCur->next = cur->next;
newCur = newCur->next;
cur->next = cur->next->next;
cur = cur->next;
}
return dummy->next;
}
};
思路2
使用哈希表来做,哈希表为 unordered_map<Node*, Node*> hash
,hash[node] = copy,也就是节点 node 对应它的拷贝 copy
因为节点和其拷贝是一一对应的,我们发现:
- hash[cur]->next 就是 hash[cur->next];
- hash[cur]->random 就是 hash[cur->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) {
if(head==nullptr) return head;
unordered_map<Node*, Node*> hash;
Node* cur = head;
while(cur!=nullptr){
Node* copy = new Node(cur->val);
hash[cur] = copy;
cur = cur->next;
}
cur = head;
Node* newHead = hash[cur];
while(cur!=nullptr){
if(cur->next!=nullptr){
hash[cur]->next = hash[cur->next];
}
if(cur->random!=nullptr){
hash[cur]->random = hash[cur->random];
}
cur = cur->next;
}
return newHead;
}
};
或者这样写(和上面的代码基本一样,做了一点简化):
/*
// 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 head;
unordered_map<Node*, Node*> hash;
Node* cur = head;
while(cur!=NULL){
hash[cur] = new Node(cur->val);
cur = cur->next;
}
cur = head;
while(cur!=NULL){
if(cur->next) hash[cur]->next = hash[cur->next];
if(cur->random) hash[cur]->random = hash[cur->random];
cur = cur->next;
}
return hash[head];
}
};