复制带随机指针的链表的最优解法

在做链表题目当中呢,会有一些比较考验思维的题目,例如 链表反转、快慢指针这样的题目,而我们今天所说的复制带随机指针的链表问题呢,是目前所接触的题目中难度算比较高的一道题,也是一些中大厂一般会考的题目,我们先来看看这道题的题目:

题目比较长,概括一下题目的意思呢就是:将题目中给出的链表进行复制,并且将链表中的值和next指针,和random随机指针一起拷贝下来形成一个新的链表,并且新链表中的任何指针都不能指向原链表中的地址。

大家肯定会有很多思路来解决这道题目,将链表拷贝下来时,不管是val和next都是比较好处理的,但是题目中的random非常难处理,它是一个随机指针,当你将一个结点拷贝下来时,你要去寻找它的random,如果用值来寻找的话,假如一个链表中有多个相同的值,如图:

 

我将原题中一个例子的第二个链表的val值改成了11,由图可以看见最后一个链表的random指向的是第二个11,如果我们用值来寻找,遍历这个链表时呢,碰到了11,那就没有办法去判断这个11是不是我们要找的了。那如何来解决这个问题呢,那我们来讲讲第一个方法的思路。

第一个方法:

那就是定义一个cur指针和一个用来计数的i:

 每当拷贝一个结点时就拿当前结点的random地址去与cur比较,当前的cur和random是否一样,如果不一样那就往下移动一个,同时int++,这样子当找到与random地址相同的cur时,同时记下了它与链表的相对位置,那我们拷贝时只要将结点的random指向第i个位置的结点,就能找到对应的结点了。

上面这种方法呢,它的时间复杂度是O(N^2),对时间复杂度来说并不是最优解,那有没有别的办法使得时间复杂度降低呢?答案是有的,解下来我们就看第二个方法。

第二个方法:

第一步,我们将每个结点都拷贝一份,并且将它就放置在每个结点的next处,如图:

 图中的意思就是将第一个结点7的next指向它的拷贝,而拷贝的next指向13,以此类推,每个结点后面都有一个与他值相同的结点,并且这个结点链向原本的第二个结点,我们这么做的目的呢就是让拷贝的链表与原链表产生关联,代码如下图所示:

第二步,就是设置每个拷贝结点中的random,那如何来设置呢,先定义一个cur指针,指向原链表中的每个结点,再定义一个copy指针,指向每个被copy的结点,再定义一个next指针,指向原链表中cur的next,定义next方便之后cur的遍历,解下来要考虑的是每个结点中的random有可能会指向空,所以第一步先去判断,当前结点的random是否指向NULL,如果指向NULL,那么拷贝结点的random也指向空,如果不是NULL,那我们就去看copy的前一个原结点也就是cur,它的random指向的是哪边的地址,而地址的next指向的就是拷贝链表的结点,用代码来表示就是:

copy->random=cur->random->next;

用图来表示:

我们需要去遍历整个链表,然后将copy的每个random找到拷贝链表的每个结点,整体的代码表示是: 

 

 第三步:

将copy链表从原链表中取下,使原链表的next指向原链表中的next,而copy链表的next指向紧接着的下一个next,我们还是需要遍历一遍链表,来修改每个原链表的结点和复制链表的结点,我们定义两个结点copyhead和copytail,当我们第一次解下拷贝链表时,copyhead就与copytail相等同时指向第一个copy结点,接下来我们只要将每个拷贝结点尾插到copytail中,最后将copyhead返回即可,我们直接上代码:

 综上,便是这道题的全部解答,题目难度尚可,大家可以作为参考,自主代入思考一下。

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值