题目描述
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例
示例 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]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
提示
-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。
题解
哈希表
遍历链表,将链表中的每个节点都复制一份,然后将原节点和复制节点的对应关系存储在哈希表中,同时连接好复制节点的 next 指针。
接下来再遍历链表,根据哈希表中存储的对应关系,将复制节点的 random 指针连接好。
算法思想如下:
- 使用一个 unordered_map<Node*, Node*> 类型的哈希表 cacheNode 来存储原链表中每个节点与其对应复制节点的映射关系。
- 创建一个新的哑节点 dummy 和一个尾节点指针 tail,用于构建复制的链表。
- 遍历原链表,对于每个节点 cur:
- 创建一个新节点,值为 cur->val,并将其添加到复制链表的尾部。
- 更新尾节点指针 tail 为新添加的节点。
- 在哈希表 d 中记录 cur 与新节点的映射关系。
- 重新将尾节点指针 tail 指向复制链表的头部(跳过哑节点)。
- 再次遍历原链表,对于每个节点 cur:
- 设置复制链表中对应节点的随机指针为原节点随机指针指向节点的复制节点。
- 更新尾节点指针 tail 为下一个节点。
- 最后返回复制链表的头部(跳过哑节点)。
/*
// 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) {
unordered_map<Node*, Node*> cacheNode;
Node* dummy = new Node(0);
Node* tail = dummy;
for (auto cur = head; cur; cur = cur->next) {
tail->next = new Node(cur->val);
tail = tail->next;
cacheNode[cur] = tail;
}
tail = dummy->next;
for (auto cur = head; cur; cur = cur->next) {
tail->random = cacheNode[cur->random];
tail = tail->next;
}
return dummy->next;
}
};
// while 替换掉
class Solution {
private:
unordered_map<Node*, Node*> cacheNode;
public:
Node* copyRandomList(Node* head) {
if (head == nullptr) return nullptr;
Node* dummy = new Node(0);
Node* tail = dummy;
Node* cur = head;
while (cur != nullptr) {
tail->next = new Node(cur->val);
tail = tail->next;
cacheNode[cur] = tail;
cur = cur->next;
}
tail = dummy->next;
cur = head;
while (cur != nullptr) {
tail->random = cacheNode[cur->random];
tail = tail->next;
cur = cur->next;
}
return dummy->next;
}
};