前言:
链表的复制,也是一个老生常谈的话题了。不过这个链表的复制,在原有链表复制的基础上,增加了一个随机位置的指针。这给我们的解题,带来了麻烦。
题干:
难度中等321收藏分享切换为英文接收动态反馈
请实现 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 。
解题思路:
我们首先对链表,按照一般链表的复制方法进行复制,即对val值赋值,建立链表的链状关系。之后,再对创建好的链表,进一步进行random赋值的操作。
对链表进行一般形态链表的复制:
需要注意的是,这个题Node类的构造函数,不存在无参的构造函数,所以,我们构造指针时,得给它象征性的传一个值:
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}//带参数的构造函数
};
指针声明时如下:
Node* copy=new Node(0);
之后进行链表的复制,在数据结构学习的时候,大家估计都操作烦了。我这里就不过多解释了,直接上代码:
Node* copy=new Node(0);
Node *pre=copy;
Node *head2=copy;
Node *to=head;
while(to!=NULL){
//赋值
copy->val=to->val;
pre->next=copy;
//创建下一个存储空间
pre=copy;
copy=new Node (0);
//向下一个地址出发
to=to->next;
}
pre->next=NULL;
这里有一个注意事项。就是复制循环结束后,其实我们并没有对最后一个链表节点的next进行赋值。因为,我们每次对next进行赋值,都是在下一个节点对pre进行赋值。借宿位置,自然就没有进行赋值喽。所以要进行pre->next=NULL;操作的补充。
对random进行赋值:
由于random的值是随机的。既有在节点前面的位置,也有在节点后面的位置。根据链表的特点,我选择先建好链表再对其进行赋值。解决这个问题的策略就是,将从链表头开始向后搜索,和从当前节点位置向后搜索,同时进行,并记录下各自的搜索次数。谁先搜索到head链表中记录random的位置,就停止。再按照记录好的搜索次数,对自己新建的链表进行copy=copy->next;操作。最后将该位置的地址给自己建立的链表的random赋值。
//对random复制
to=head;
copy=head2;
Node *v=NULL;
Node *hea=NULL;
Node *ran=NULL;
int tot1=0,tot2;
while(to!=NULL){
ran=to->random;
if(ran==NULL){
copy->random=NULL;
//向下一个位置出发
to=to->next;
copy=copy->next;
}
else{
tot1=0;//记录前到后
tot2=0;//记录后到前
v=to;//当前向后
hea=head;//头向后
//找random的位置
while(true){
//找到
if(v==ran){
v=copy;
for(int i=1;i<=tot2;i++){
v=v->next;
}
copy->random=v;
break;
}
else if(hea==ran){
v=head2;
for(int i=1;i<=tot1;i++){
v=v->next;
}
copy->random=v;
break;
}
//未找到
tot1++;
tot2++;
v=v->next;
if(v==NULL){
v=to;
}
hea=hea->next;
}
//向下一个位置出发
copy=copy->next;
to=to->next;
}
}
其中值得一说的是,我们对当前位置向后进行搜索很可能在没搜索到目标值的情况下,已经到头了。所以我们需要对该语句增加一个状态更新
if(v==NULL)
{
v=to;
}
因为出现这种情况的时候,已经可以确定,我们要找的目标不在当前位置的后面。所以此时,不管怎么对这个值进行更新,都没关系。
我的题解:
/*
// 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==NULL){
return NULL;
}//判空
Node* copy=new Node(0);
Node *pre=copy;
Node *head2=copy;
Node *to=head;
while(to!=NULL){
//赋值
copy->val=to->val;
pre->next=copy;
//创建下一个存储空间
pre=copy;
copy=new Node (0);
//向下一个地址出发
to=to->next;
}
pre->next=NULL;
//对random复制
to=head;
copy=head2;
Node *v=NULL;
Node *hea=NULL;
Node *ran=NULL;
int tot1=0,tot2;
while(to!=NULL){
ran=to->random;
if(ran==NULL){
copy->random=NULL;
//向下一个位置出发
to=to->next;
copy=copy->next;
}
else{
tot1=0;//记录前到后
tot2=0;//记录后到前
v=to;//当前向后
hea=head;//头向后
//找random的位置
while(true){
//找到
if(v==ran){
v=copy;
for(int i=1;i<=tot2;i++){
v=v->next;
}
copy->random=v;
break;
}
else if(hea==ran){
v=head2;
for(int i=1;i<=tot1;i++){
v=v->next;
}
copy->random=v;
break;
}
//未找到
tot1++;
tot2++;
v=v->next;
if(v==NULL){
v=to;
}
hea=hea->next;
}
//向下一个位置出发
copy=copy->next;
to=to->next;
}
}
return head2;
}
};
时间效率上是没问题的,就是有点耗内存