【算法】如果链表里有随机指针怎么拷贝?-【力扣-138】复制带有随机指针的链表-力扣经典题目讲解【带图】【保姆级别教程】
【算法】如果链表里有随机指针怎么拷贝?-【力扣-138】经典题目讲解【保姆级别教程】
先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注我哦!️️️
题目:力扣OJ138-复制带随即指针的链表
本篇建议收藏后食用~
题目
分析
题目初步分析:
看完这道题,我们首先要知道的-什么是带有随机指针的链表。
当然,题目写的太“高级”,感觉很厉害的样子,其实没那么难理解
我们通过leetcode提供给我们的结构图,我们可以看到。
这个特殊的链表总体结构上是一个单链表,与单链表不同的是,这个链表的每一个结点里多了一个random
指针,它指向的结点是不确定的。有可能指向第一个结点,有可能指向第二个,有可能指向它自己,有可能指向NULL
。这就给我们的拷贝制造了很多麻烦。
当然,这道题对于初学数据结构的伙伴来说,算是一道比较难的题目了,所以,看完这篇博客,相信我们可以很好地解决这个问题,并且我相信我们的能力,会有一个层次的提升。
一些关于学数据结构的提醒
我曾经在以前的博客里面讲过,学习编程,特别是学到指针,数据结构这些内容的时候。画图是非常重要的,这些题目,虽然我学习的时间并不是很久,但是我可以很负责任地说,学编程,不画图,一定学不好。伙伴们看看这道题,不画图根本不可能想得出来。
算法及实现
链表结构
struct Node {
int val;
struct Node *next;
struct Node *random;
};
解题思路
首先:想要解决这一道题,想要直接拷贝是肯定不行的,如果我们拷贝出来的空间不和原来的结点有联系的话,
random
是处理不了的。
所以,我们的新开辟出来的结点一定要和原来的结点有联系。因此
第一步:将新拷贝的结点链接到我们原来的结点的后面。并重新链接起来。做完这个步骤,原来三个结点的链表会变成六个结点,原来四个结点的链表会变成八个结点。
即如图所示
做完这一步,我们新拷贝的结点就和我们原来的结点建立了联系。
第二步: 处理
random
指针: 做完第一步之后,我们要敏锐地发现,拷贝出来的结点的random所指向的结点,应该是原来结点的random所指向的结点的后面那个结点。这样我们的random不就可以处理了吗。
我们再梳理一次上面那句话:新拷贝出来的结点的random指向原来拷贝出来的random所指向的结点的后面那个结点(当然,如果原来random指向的是NULL
,那我们新random也直接指向NULL
就可以了,这里记得判断一下
,否则容易造成对空指针解引用的问题,导致OJ过不了。) 这个就是整道题的精髓所在,处理random的方法。
做完第二步之后,我们就处理好了random
指针的问题,最麻烦的一步解决了。
第三步:断开新链表和旧链表的联系
目前的状况是这样子的:(由于加上random的箭头,版面太乱了,图片里就不加上箭头了,用“已处理好”代替)
现在需要做的,就是断开二者联系,使它成为一个独立链表。
首先,我们需要三个指针,防止结点的丢失:cur(用于遍历),copy(cur后面拷贝的结点),next(copy后面的那个结点,也就是原链表cur后面的那个结点)
。
这里只要注意一下拆指针的顺序即可,这一部分我们在其它的题也接触很多了。这里就不赘述了。
完整代码
struct Node* copyRandomList(struct Node* head) {
if (head == NULL) {//防止传进来空链表
return NULL;
}
struct Node* cur = head;
//1.拷贝链表,放到原来结点的后面
while (cur) {
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->next = NULL;
copy->val = cur->val;
copy->next = cur->next;//先让新的指向后面
cur->next = copy;//然后再让前面的指向新的
//注意顺序
//让指针动起来(迭代)
cur = cur->next->next;
}
//2.处理random
cur = head;//cur重新来过
while (cur) {
struct Node* copy = cur->next;
//写链表一定要细心再细心
//题目说random有可能为空,所以:
if (cur->random != NULL) {//记得判断一下
copy->random = cur->random->next;//关键
}
else {
copy->random = NULL;
}
//迭代
cur = cur->next->next;//因为中间间隔了一个拷贝结点
}
//3.拆
//这里一定要画图分析注意一下
//三个指针,cur copy next,当走到最后一步的时候,next已经是空了,这个时候copy=copy->next->next就不对了,应该直接置成空
//此时我们发现,我们的函数是要返回新的头结点的,但是我们弄丢了,所以要保存
cur = head;
struct Node* copyhead = head->next;//先保存头
while (cur) {
struct Node* copy = cur->next;
struct Node* next = copy->next;
cur->next = next;
if (next != NULL) {//最后一步防止next已经为空了
copy->next = next->next;
}
//迭代
cur = next;
}
return copyhead;
}
尾声
以上就是这期博客所带来的-复制带有随机指针的链表的力扣经典题。这题对于初学者来说难度确实有点高。但是相信看到这里的伙伴,应该已经可以基本完成这道题了。这边建议下去以后我们再独立做一遍。如果你感觉这篇博客对你有帮助的话,别忘了点赞关注收藏转发哦!你们的支持是我必不可少的动力