复制带随机指针的链表 链表的深度拷贝 中等
题目介绍
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
思路:
方法一:使用hashmap
需要为 random 指针和 next 指针指向的未访问过节点创造新的节点并赋值即可。
1、从 head 节点开始遍历链表。下图中,我们首先创造新的 head 拷贝节点。拷贝的节点如下图虚线所示。实现中,我们将该新建节点的引用也放入已访问映射中。
2、random 指针
2.1如果当前节点i的 random 指针指向一个节点 j 且节点 j 已经被拷贝过,我们将直接使用已访问字典中该节点的引用而不会新建节点。
2.2如果当前节点 i 的 random 指针指向的节点 j 还没有被拷贝过,我们就对 j 节点创建对应的新节点,并把它放入已访问节点映射中。
/*
// 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:
//方法1
Node* copyRandomList(Node* head)
{
if (head == NULL)
return head;
//遍历原链表 创建新链表节点并建立映射关系
unordered_map<Node*, Node*> map; //<原链表节点,对应位置的新链表节点>
Node* cur = head;
while (cur)
{//创建key = 老节点的指针 value = 新节点的指针 的映射
//并利用构造函数将老节点的值赋值给新节点
//此时新节点已经创建,但是还没有连接也就是说next和random都是NULL。
map[cur] = new Node(cur->val);
cur = cur->next;
}
//遍历原链表 根据map链接新链表
cur = head;
while (cur)
{
Node* node = map[cur];//创建新节点的指针,用于后面连接
node->next = map[cur->next];//连接next节点
node->random = map[cur->random];//连接random节点
cur = cur->next;//后移
}
return map[head];//返回映射对应的头结点的value值
}
};
2、复制节点并插入当前节点后面
2.1、复制节点并插入当前节点后面;
2.2、再设定好random指针;
2.3、最后分离出原链表与副本链表
如: 1->2->3->null ==》 1->1’->2->2’->3->3’->null ; 再分离出 1->2->3->null 与 1’->2’->3’->null
此方法没看呢
//方法2
Node* copyRandomList(Node* head)
{
if (!head)
{
return head;
}
//复制节点 (遍历链表 在当前节点后插入副本节点)
Node* cur = head;
while (cur)
{
Node* node = new Node(cur->val);
Node* next = cur->next;
node->next = next;
cur->next = node;
cur = next;
}
//对副本节点设置random指针
cur = head;
while (cur) //因为复制了节点,cur->next不会为空 最终是cur为空
{
cur->next->random = cur->random ? cur->random->next : nullptr; //注意:原链表中cur->random可能为空
cur = cur->next->next;
}
//分离出原链表与副本链表
cur = head;
Node* new_head = head->next; //副本链表的头节点
Node* new_tail = new_head; //副本链表的尾节点
while (cur)
{
cur->next = cur->next->next;
cur = cur->next;
new_tail->next = cur ? cur->next : nullptr; //注意:最后cur为空的情况
new_tail = new_tail->next;
}
return new_head;
}