138.复制带随机指针的链表 (Medium)*
题目描述*
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
- val:一个表示 Node.val 的整数。
- random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
提示*
-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。
代码*
带随机指针的链表深拷贝主要的问题就是在设置 random 指针时指向的结点可能还未创建。因此想到把链表项复制后存入哈希表,然后再设置 next 和 random 指针。这需要两次遍历,可以优化为一次遍历,即如果 random 对应的结点尚未复制,则复制存入哈希表;已复制则直接设置。
另有一种做法就是先把链表复制,新生成的结点在原结点后,然后分离出来,leetcode 上看到有人称之为 有丝分裂,感觉挺形象。此方法使用原链表的 next 域保存新结点,那么我们同样可以用 random 域保存新结点,然后再分离。
class Solution {
public:
Node* copyRandomList(Node* head) {
Node *p = head;
Node *tail = new Node(-1);
unordered_map<Node*, Node*> saveMap;
Node *tmp;
int cnt = 0;
while(p != nullptr) {
if(saveMap.find(p) == saveMap.end()) {
tmp = new Node(p->val);
saveMap[p] = tmp;
}
Node *copied = saveMap[p];
if(p->random != nullptr) {
if(saveMap.find(p->random) == saveMap.end()) {
tmp = new Node(p->random->val);
saveMap[p->random] = tmp;
copied->random = tmp;
}else {
copied->random = saveMap[p->random];
}
}
tail->next = copied;
tail = tail->next;
p = p->next;
cnt++;
}
return saveMap[head];
}
};
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr) {
return nullptr;
}
Node *cur = head, *copied = nullptr;
// copy 所有结点直接放到原结点后
while(cur != nullptr) {
copied = new Node(cur->val);
copied->next = cur->next;
cur->next = copied;
cur = cur->next->next;
}
// 设置 random 指针
cur = head;
while(cur != nullptr) {
if(cur->random != nullptr) {
cur->next->random = cur->random->next;
}
cur = cur->next->next;
}
// 分离复制链表
cur = head;
Node *res = cur->next;
while(cur != nullptr) {
copied = cur->next;
cur->next = copied->next;
if(copied->next != nullptr) {
copied->next = copied->next->next;
}
cur = cur->next;
}
return res;
}
};
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr) {
return nullptr;
}
// 与上一种类似,只是换成了 random
Node *cur = head, *copied = nullptr;
while(cur != nullptr) {
copied = new Node(cur->val);
copied->next = cur->random;
cur->random = copied;
cur = cur->next;
}
cur = head;
while(cur != nullptr) {
copied = cur->random;
copied->random = (copied->next == nullptr) ? nullptr : copied->next->random;
cur = cur->next;
}
cur = head;
Node *res = cur->random;
while(cur != nullptr) {
copied = cur->random;
cur->random = copied->next;
copied->next = (cur->next == nullptr) ? nullptr : cur->next->random;
cur = cur->next;
}
return res;
}
};
最后更新: July 23, 2022