复杂链表的复制
请实现 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 。
解法: 为了提高时间复杂度和空间复杂度的效率,采用复制结点到原链表上,然后再将原链表拆分成两条。
第一步:克隆结点
第二步:复制结点的random值到子结点上
第三步:将链表拆分成两条
遇到的问题: 此题涉及到的复制和断链过程比较复杂,中间多次出错。指针的指向问题的技巧也要多总结。
TODO: 指针的指向技巧总结
/*
// 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) {
if(head == nullptr)
return nullptr;
cloneNode(head);
connectNode(head);
return reConnectNode(head);
}
// 将所有结点克隆一份,跟在自己后面
void cloneNode(Node*& head){
Node* pNode = head;
while(pNode != nullptr){
Node* newNode = new Node(head->val);
newNode->val = pNode->val; // 注意这里的初始化
newNode->next = pNode->next;
newNode->random = nullptr;
pNode->next = newNode;
pNode = newNode->next;
}
}
// 将原链表中的random信息赋值到复制的链表中
void connectNode(Node*& head){
Node* pNode = head;
while(pNode != nullptr){
Node* nextCloned = pNode->next;
if(pNode->random != nullptr){
nextCloned->random = pNode->random->next;
}
pNode = nextCloned->next;
}
}
// 根据奇数和偶数将结点拆分为两条,一条为原始链,一条为复制链。
Node* reConnectNode(Node*& head){
Node* pNode = head;
Node* clonedHead = pNode->next;
Node* nextCloned = clonedHead;
pNode->next = nextCloned->next; // 注意
pNode = pNode->next;
while(pNode != nullptr){
nextCloned->next = pNode->next;
nextCloned = nextCloned->next; // 注意
pNode->next = nextCloned->next;
pNode = pNode->next;
}
return clonedHead;
}
};