一、问题描述
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
二、解题思路
第一种:用hashmap,遍历链表然后把它存到 HashMap 中,val 作为 key,Node 作为 value。遍历第二遍链表,将之前生成的节点取出来,更新它们的 next 和 random 指针。查找复杂度为 O(1) ,这样可以把总时间复杂度降到 O(n) ,由于要暂存所有节点,其空间复杂度为 O(n)。
第二种:三次遍历得到结果,先把每个节点拷贝,并把拷贝节点连接到原节点后面,依次类推。确定随机节点的关系之后再拆分链表。
三、代码实现
第一种:
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node() {}
Node(int _val, Node* _next, Node* _random) {
val = _val;
next = _next;
random = _random;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
if (head == nullptr) {
return head;
}
Node *cur = head;
map<Node*, Node*> map;
//1. 遍历链表,将原节点作为key,拷贝节点作为value保存在map中
while (cur != nullptr) {
//原来是1->2->3->4,现在map中存入的是[1,1],[2,2],[3,3],[4,4]
Node *copy = new Node(cur->val);
map[cur] = copy;
cur = cur->next;
}
//2. 复制链表next和random指针
//1的random是3;2和3的为空;4的是2
cur = head;
while (cur != nullptr) {//以1为例
//1->2
map[cur]->next = map[cur->next];
//1 random->3
map[cur]->random = map[cur->random];
//下一个结点
cur = cur->next;
}
return map[head];
}
};
第二种:
class Solution {
public:
Node* copyRandomList(Node* head) {
if (head == nullptr) {
return head;
}
Node *node = head;
//1. 将复制节点添加到原节点后面:1->1->2->2->3->3->4->4
while (node != nullptr) {
Node *copy = new Node(node->val, nullptr, nullptr);
copy->next = node->next;
node->next = copy;
node = copy->next;
}
//2. 复制random节点
node = head;
while (node != nullptr) {
if (node->random != nullptr) {//以1为例
//第二个1指向3
node->next->random = node->random->next;
}
//走两步
node = node->next->next;
}
//3. 分离链表(将链表断开成1->2->3->4,此时之前第二个1、2、3、4都已经为random了)
node = head;
Node *newHead = head->next;
Node *newNode = newHead;
while (node != nullptr) {
node->next = node->next->next;
if (newNode->next != nullptr) {
newNode->next = newNode->next->next;
}
node = node->next;
newNode = newNode->next;
}
return newHead;
}
};