剑指offer-复杂链表的复制
题目描述:
复制一个链表是较为简单的,对原链表一次遍历就可以完成,此题难点就在于如何复制链表上的这些random指针,它们在目标链表上是随机指向的。
思路1:暴力解法,对一个节点的random节点在非空情况下,在链表中查找在此节点的坐标(假想链表是一个一维坐标)通过计数器可以计数得到,然后对复制节点重复此过程对对应节点的random进行赋值。
/*待添加*/
思路2:创建哈希表,上面问题时间复杂度为O(n^2),关键在于对每个待复制节点都需要从原链表中从头到尾的重新扫描找到random指向节点,但通过哈希映射就可以将该过程省略,创建映射关系:f<a,a’>…f<c,c’>…如果有a->random = c 则有f(a).random=f(c).
/*待添加*/
思路3:思路2中完成了原链表中由random建立的两个节点的关系和待复制节点与复制节点直接的映射关系,其时间复杂度为O(n),通过建立映射的方式还可以进行进一步的升级,将复制节点放在原链表相应节点之后,然后通过三步即可完成同样功能,第一步:将链表复制的节点放在相应节点之后,对节点值进行赋值和初始化,第二步:对复制链表的random进行赋值,假设前一节点是原链表中节点a,当前节点为a’,当a->random非空时,存在a’->random = a->random->next这种关系。可以画图了解,第三步:将原链表与复制链表分离。返回复制链表头结点,代码描述如下:
/*
// 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) {
CloneNodes(head);
ConnectRandomNodes(head);
return ReconnectNodes(head);
}
void CloneNodes(Node* head){ //将节点N'赋值放在N节点后
Node* pNode = head;
while(pNode!=nullptr){
Node* pCopynode = new Node(pNode->val);
pCopynode->next = pNode->next;
pNode->next = pCopynode;
pNode = pCopynode->next;
}
}
void ConnectRandomNodes(Node* head){
//将新创建节点的random进行赋值,通过node->random->next来初始化
Node* pNode = head;
while(pNode!=nullptr){
Node* pCopyNode = pNode->next;
if(pNode->random!=nullptr){
pCopyNode->random = pNode->random->next;
}
pNode = pCopyNode->next;
}
}
Node* ReconnectNodes(Node* head){
Node* pNode = head;
Node* pCopyHead = nullptr;
Node* pCopyNode = nullptr;
if(pNode!=nullptr){
pCopyHead = pNode->next;
pCopyNode =pNode->next;
pNode->next = pCopyNode->next;
pNode = pNode->next;
}
while(pNode!=nullptr){ //先对copy节点进行处理否则还需加条件限制
pCopyNode->next = pNode->next;
pCopyNode = pCopyNode->next;
pNode->next = pCopyNode->next;
pNode = pNode->next;
}
return pCopyHead;
}
};