当前位置:   article > 正文

力扣138 - 复制带随机指针的链表【复杂链表的终极试炼】

力扣138 - 复制带随机指针的链表【复杂链表的终极试炼】

一、题目描述

原题传送门

在这里插入图片描述

示例 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]]

提示:

  • 0 <= n <= 1000
  • -104 <= Node.val <= 104
  • Node.random 为 null 或指向链表中的节点。

此题是力扣上一道中等难度的题目,不过相信很多同学在看了这道题目之后都点云里雾里的感觉,觉得这道题很复杂的样子,一个链表有两个指针域,而且有一个还是随机指针,对于题目的描述完全不读懂它在讲点什么。

是的,这道题虽说是中等难度的题目,但是在我看来本题算是链表章节的题目中比较综合的题,虽然它没有【环形链表】那么绕,需要一些数学的思维,但它的结构是比较复杂的,需要做题者对于链表的掌握程度达到一定的水准,不然得话在处理其指针的关系时就会思绪混乱、无从下手

二、思路分析与罗列

思路一:通过原链表的【random】去找控制拷贝链表的【random】

  • 首先来理一下这个题目的思路,其实把这就是一个单链表,只是它存在一个随机指针罢了,那题目的意思就是复制每一个结点,而且复制出来的结点不可以指向原链表中的结点,也就是要重新修改指向,对于这个【random】指针也需要有一个复制。那其实可以看到,就是完整地将这个链表复制一份出来

在这里插入图片描述

  • 那有同学就说,这不是很简单,把每一个结点做一个拷贝,然后再将它们做一个链接,之后再将【random】指针也做一个相同的指向不就好了。【next】指针确实可以做一个链接,但是你觉得这个【random】指针也可以直接这样做一个链接吗?

在这里插入图片描述

  • 就好比这里的【13】,原链表中是指向7,现在可以指向7,;对于【11】,原链表是指向1,那是在下午我做了一个修改后,现在有两个1了,那指向哪个呢?一般来说都是默认前面那个,因为单链表只能从前往后遍历,那算你能从后往前遍历,【1】是指向【7】的,但是后面又出现一个【7】怎么办呢,那又会出现混乱。所以我们不可以直接指向其原来的位置,要指向哪里?–》相对位置

在这里插入图片描述

  • 这个时候我们就需要去找到这个相对位置,不是去找你【random】值向的值是第几个,而是寻找【random】指向的那个地址,根据地址去进行一个查找。也就是通过原链表的【random】去控制拷贝链表的【random】
  • 首先看到【7】,原链表的【random】指向【NULL】,那拷贝链表也就指向它这里的【NULL】,根据【copy】和【cur】当前所指的值进行一个对比
  • 此时我们需要定义一个变量【i】去寻找当前原链表【cur】的【random】所指向的地址,那此时这个【i】就需要一直去遍历,找到原链表中的【NULL】

在这里插入图片描述

  • 此时就需要这个【i】去遍历这个链表进行查找,【i++】就会加到5,此时拷贝链表只需要进行一个【while(i–)】,就可以找到它那里的这个【NULL】了

在这里插入图片描述

  • 然后【cur】和【copy】后移继续更新【random】,但是【i】不需要动,此时原链表中的【1】指向位置为0的【7】,因此拷贝链表也指向位置为0的【7】

在这里插入图片描述

  • 然后继续进行一个迭代,此时原链表中的【11】指向的是后面的那个【1】,于是下标【i】就开始寻找指向的那个地址

在这里插入图片描述

  • 然后【i】去寻找,找一个【++i】,找一个【++i】,直到找到原链表的这个结点的【random】指向的地址为止

在这里插入图片描述

  • 然后拷贝链表也需要做这么一个修改,后面的也是类似,便不细讲

在这里插入图片描述

  • 我们来分析一下思路,大家认为这个思路的【时间复杂度】是多少,我们知道,时间复杂度是要算最坏的,那我举一个例子,例如说这个【7】,它是指向【NULL】的,然后这个【1】和【11】,我现在做一个修改,让它们也去指向这个【NULL】,那此时这个原链表和拷贝链表都需要遍历【N】次才可以找到这个位置,所以时间复杂度很可能到达O(N2)
  • 那O(N2)这个时间复杂度是不是太高了,于是我们就需要开始思考有没有O(N)的思路可以实现的,你能想到到吗?接下来我们再来讲一种思路

思路二:直接链接到原链表处做相邻结点的【random】修改

先行说明,这种思路的时间复杂度是O(3N),最后进行大O渐进法的优化就是O(N)

  • 好,接下去我们就来讲讲这种思路,它一共分为三步
Step1:把复制的结点插入到原结点后
  • 首先是第一步,从下图可以看到,我们定义一个【cur】指向原链表的结点,然后根据这个结点去【malloc】出一个新的结点,之后让他们的【val】值都相同
  • 接下去我们要修改的就是【next】指针域,这个很容易,保存一下当前【cur】结点的下一个结点,然后将【copy】结点和它们进行一个互连即可,链接好后做一个迭代更新

在这里插入图片描述

  • 展示一下核心代码

Node* cur = head;
while(cur)
{
Node* copy = (Node *)malloc(sizeof(Node));
copy->val = cur->val;

//插入结点
Node* nextNode = cur->next;
cur->next = copy;
copy->next = nextNode;

//迭代
cur = nextNode;
}

Step2:设置拷贝结点的random值【⭐⭐⭐】
  • 好,接下去我们开始做第二步,就是去设置每个【copy】结点的【random】指针指向。这一步非常得关键:
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/737860
推荐阅读
相关标签