题目描述:
请实现 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 。来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:本来以为这道题会简单一些,但是写着写着发现不是这样的,有几个问题:
1.random指向的节点可能当时还并未创建
2.节点的value是可能相同的
于是,我能想到的办法就是,先遍历第一遍,不管random,按照next的顺序,复制出来链表。然后遍历第二遍,针对原链表节点中的random,来寻找该random指向的节点在原链表中的位置(第k个),然后再去复制的链表中,找到第k个节点,把它连接到random上。事实证明也通过了,下面附上代码:
/*
// 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) {
Node *res=new Node(0);
Node *head1=res;
if(head==NULL) return NULL;
Node *p=head;
while(p!=NULL)
{
Node *temp=new Node(p->val);
res->next=temp;
res=res->next;
// if(p->random==NULL)
// res->random=NULL;
// else
// res->random=new Node(p->random->val);
p=p->next;
}
p=head;
res=head1->next;
while(p!=NULL)
{
if(p->random==NULL)
res->random=NULL;
else
{
int k=findinhead(head,p->random);
if(k!=-1)
{
Node* temp=findinhead1(head1,k);
res->random=temp;
}
else
{
res->random=NULL;
}
}
p=p->next;
res=res->next;
}
return head1->next;
}
int findinhead(Node *head,Node *random)
{
int res=0;
while(head!=NULL)
{
if(head==random)
return res;
head=head->next;
res++;
}
return -1;
}
Node *findinhead1(Node *head1,int k)
{
head1=head1->next;
if(k==0) return head1;
while(k--)
{
head1=head1->next;
}
return head1;
}
};
然而这个方法肯定不是最简单的,因为遍历了好几次链表,有没有只用遍历一次就可以完成链表的深拷贝呢?我想不出来,看了看题解,如果用hash表的话,或许可以实现。
思路如下:
遍历节点的时候,节点的next和random如果未创建,那么就创建节点,并把指针保存到hash表中,当再次用到该节点时,再去hash表里寻找。如果hash表中没有,再进行创建。
代码如下:
/*
// 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) {
// 创建hash表
unordered_map<Node* ,Node*> map;
Node *p=head;
// 伪头节点
Node *head1=new Node(0);
Node *p1=head1;
// 原链表进行遍历
while(p!=NULL)
{
// 如果该节点未被创建
if(map.find(p)==map.end())
{
// 创立新节点并连接
Node *temp=new Node(p->val);
p1->next=temp;
p1=p1->next;
map.insert(make_pair(p,temp));
}
else
{
// 如果该节点已经被创建
// 找到该节点并连接
auto it=map.find(p);
p1->next=it->second;
p1=p1->next;
}
if(p->random==NULL)
p1->random=NULL;
else
{
// 如果random未被创建
if(map.find(p->random)==map.end())
{
// 创建并连接
Node *temp=new Node(p->random->val);
p1->random=temp;
map.insert(make_pair(p->random,temp));
}
else
{
// 如果random已经创建
// 找到并连接
auto it=map.find(p->random);
p1->random=it->second;
}
}
p=p->next;
}
return head1->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:
unordered_map<Node*,Node*> map;
Node* copyRandomList(Node* head) {
// 如果当前节点为空,就返回NULL
if(head==NULL)
return NULL;
// 如果当前节点没有被创建
if(map.find(head)==map.end())
{
// 创建当前节点
Node *temp=new Node(head->val);
// 当前节点存入hash表
map[head]=temp;
// 递归的方法,来对temp->next和temp->random进行赋值
temp->next=copyRandomList(head->next);
temp->random=copyRandomList(head->random);
}
// 如果当前节点已经创建,直接从hash表里找到,并返回即可
return map[head];
}
};