一、题目描述与要求
复杂链表的复制_牛客题霸_牛客网 (nowcoder.com)
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。
示例:
输入:{1,2,3,4,5,3,5,#,2,#}
输出:{1,2,3,4,5,3,5,#,2,#}
解析:我们将链表分为两段,前半部分{1,2,3,4,5}为ListNode,后半部分{3,5,#,2,#}是随机指针域表示。
以上示例前半部分可以表示链表为的ListNode:1->2->3->4->5
后半部分,3,5,#,2,#分别的表示为
1的位置指向3,2的位置指向5,3的位置指向null,4的位置指向2,5的位置指向null
如下图:
示例
示例1:
输入:{1,2,3,4,5,3,5,#,2,#}
返回值:{1,2,3,4,5,3,5,#,2,#}
二、解题思路
根据题目描述我们需要自己创建新的链表并且将原来的链表的每个结点进行深拷贝到结点,也就是说我们新创建的结点不能够通过=p->random等来实现创建,而是需要创建自己的结点,并且使随机指针指向对应的新结点。
首先为了能够复制每一个结点,我们还是需要创建一个新的头结点。用来与新链表的第一个结点进行连接。此时还要分别定义两个指针,用来遍历新链表和旧链表。要实现结点的复制及其一一对应的关系,我们可以利用哈希表,令哈希表的key位原链表的结点,value即为新链表的结点,这样我们就可以实现新链表和旧链表一一对应的关系。
通过遍历原链表,我们利用new来创建新结点并且将对应原结点的值通过构造函数进行赋值,然后将新结点存入map表,接着就是在新链表实现连接。这一步完成就实现了新链表结点的创建与连接,但是random指针还没有实现。
接着我们就可以利用哈希表的特点,判断一下原结点的random指针指向,如果指向空,那就直接将对应新结点的random指针也指向空;如果不为空,那我们就需要知道原结点的random指针指向哪个结点,然后在map中找到对应的新结点赋值给新结点的random指针。
最后返回L->next即可。
三、具体代码
#include <unordered_map>
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead) {
if(pHead==nullptr) return pHead;
RandomListNode* L=new RandomListNode(0);//新的头结点
//哈希表,key为原始链表结点,value为拷贝链表的结点
unordered_map<RandomListNode*, RandomListNode*> map;
RandomListNode *cur=pHead;
RandomListNode *pre=L;
//遍历原始链表进行复制 同时实现next指针的指向
while(cur){
//拷贝结点
RandomListNode *clone=new RandomListNode(cur->label);
//用哈希表记录结点
map[cur]=clone;
//连接
pre->next=clone;
pre=pre->next;
//遍历
cur=cur->next;
}
//实现random指针指向
for(auto node:map){
if(node.first->random==nullptr){//原结点的随机指针指向空,则新结点也指向空
node.second->random=nullptr;
}
else{//否则的话找到原节点random指针指向的结点对应的复制结点
node.second->random=map[node.first->random];
}
}
return L->next;
}
};