原题链接: 138. 复制带随机指针的链表 - 力扣(Leetcode)
tag: 链表.
一. 题目
给你一个长度为 n 的链表, 每个节点包含一个额外增加的随机指针 random , 该指针可以指向链表中的任何节点或空节点.
构造这个链表的 深拷贝. 深拷贝应该正好由 n 个 全新 节点组成, 其中每个新节点的值都设为其对应的原节点的值. 新节点的 next 指针和 random 指针也都应指向复制链表中的新节点, 并使原链表和复制链表中的这些指针能够表示相同的链表状态. 复制链表中的指针都不应指向原链表中的节点 .
例如, 如果原链表中有 X 和 Y 两个节点, 其中 X.random --> Y . 那么在复制链表中对应的两个节点 x 和 y , 同样有 x.random --> y .
返回复制链表的头节点.
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val: 一个表示Node.val的整数.random_index: 随机指针指向的节点索引 (范围从0到n-1) ; 如果不指向任何节点, 则为null.
你的代码 只 接受原链表的头节点 head 作为传入参数.
二. 题解
本题按照如下四步进行理解.
1. 在原链表的每一个节点后复制出一个相同的节点
Node* curr = head;
curr != nullptr
Node* newnode = new Node(curr->val);
newnode->next = curr->next;
curr->next = newnode;
curr = curr->next->next;
重复这一步骤.
直到 curr == nullptr.
2. 修改复制出的新节点的 random 指针的指向
Node* curr = head;
curr != nullptr
curr->random == nullptr
curr = curr->next->next;
curr != nullptr
curr->random != nullptr
修改拷贝节点 random 指针的指向.
curr->next->random = curr->random->next;
curr = curr->next->next;
重复这一步骤.
直到 curr == nullptr.
3. 将拷贝节点逐个尾插到虚拟头节点的后面, 并对原链表中的节点与拷贝节点进行拆分
Node* dummy = new Node(0), * tail = dummy;
Node* curr = head;
curr != nullptr
Node* newnode = curr->next;
改变拷贝节点的 next 指针指向.
tail->next = newnode;
tail = tail->next;
恢复原链表节点 next 指针的指向.
curr->next = newnode->next;
curr = curr->next;
重复这一步骤, 直到 curr == nullptr.
4. 返回原链表的深拷贝
head = dummy->next;
delete dummy;
return head;
三. 复杂度分析
时间复杂度: O(N), 其中 N 是链表的长度, 我们需要遍历原链表三次.
空间复杂度: O(1).
四. 代码
/*
// 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) {
for (Node* curr = head; curr; curr = curr->next->next) {
Node* newnode = new Node(curr->val);
newnode->next = curr->next;
curr->next = newnode;
} // 在原链表的每一个节点后复制出一个相同的节点
for (Node* curr = head; curr; curr = curr->next->next) {
if (curr->random != nullptr) {
curr->next->random = curr->random->next;
}
} // 修改复制出的新节点的 random 指针的指向
Node* dummy = new Node(0), * tail = dummy;
for (Node* curr = head; curr; curr = curr->next) {
Node* newnode = curr->next;
tail->next = newnode;
tail = tail->next;
curr->next = newnode->next;
} // 将拷贝节点逐个尾插到虚拟头节点的后面, 并对原链表中的节点与拷贝节点进行拆分
head = dummy->next; // 返回原链表的深拷贝
delete dummy;
return head;
}
};