算法题解记录27+++随机链表的复制(百日筑基)

一、题目描述:

        题目难度:中等

        给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

        构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 

        例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

        返回复制链表的头节点。

        用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码  接受原链表的头节点 head 作为传入参数。

示例 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
  • -10^4 <= Node.val <= 10^4
  • Node.random 为 null 或指向链表中的节点。

二、解题准备

        1.了解题意:

        题目要求拷贝链表,需要注意的是,本题链表的定义和普通链表不同,本题链表的节点,除了val域和next域,还有一个random域,随机指向本链表的某一节点【但是这链表肯定不是环形链表】

        深度拷贝,要求复制出一个一模一样的链表,这种链表,除了val域一样,next域指向新节点外,random域指向的节点,不能是原先链表的节点。

        用3元式表示一个节点【val,next,random】,其中,@x表示指向第x个节点,这个x从0开始。

        举个例子,我们有一个链表【1,@1,@NULL】,【4,@2,@3】,【10,@3,@0】,【7,@NULL,@NULL】

        这个链表类似于下图【不懂绘图,勉强看吧】

        我们需要的新链表,要与这个一模一样,但是是下图这样的:

        至此你应该理解了题意。

        

        2.基本操作:

        本题涉及链表的创建和增加。

        3.基础原理:

        对于链表题目,要记住最基础的一个方法(如何遍历链表):

        如果是使用迭代while,那么,基础的迭代语法就是:

Node temp = head; // 防止遍历结束后,丢失读取链表的方法
while(temp!=null){print(temp.val); // 伪代码,访问temp的数据temp = temp.next;
}
// 结束条件:最终temp指向第一个null“节点”

三、解题思路

        首先考虑,如果去除random域,那么如何复制一份链表?

        1.简化思路:最基本的链表拷贝方法

        拷贝一个链表,其实是拷贝链表的val域,以及链表节点之间的相互关系。

        比如上面说的例子【1,4,10,7】。我们知道链表间的关系就是1指向4,4指向10,10指向7。

        由于链表的next域自带这种联系方式,所以拷贝的时候,不必把相互关系存储起来,而是在遍历时,一边拷贝即可。

        也就是说,我们首先创建一个对象res,指向head(或者用哑节点也行,无所谓)

        然后,遍历原链表,同时不断创建新结点。

        代码如下:

        Node res = new Node(head.val); // 指向头节点temp = head.next; // 如果指向head,那么while中会拷贝len次,而res已经拷贝一次real = res; // 指向头节点,避免丢失res// 一直迭代到temp指向第一个null节点。while(temp!=null){// 为什么用next?因为如果用real本身,会丢失联系。// 解释:real原先是一个null节点,你new之后,前面的联系就断了real.next = new Node(temp.val);temp = temp.next;real = real.next;}return res; // res就是我们要的答案

        得到拷贝基础链表的方法后,开始考虑本题的random域链表。

        我们首先要确定一件事:

        拷贝一个数据结构,就是拷贝元素值,以及元素之间的相互关系。

        如果进行一遍“简化思路”,那么,除了random域的元素关系,其它的元素关系都被拷贝了。

        所以,只需要考虑如何把random域的元素关系拷贝即可。

        2.思路:存储random域的元素关系

        如题,由于random是随机指向某个节点的,而链表不支持随机访问,也不能知道某个节点,在整个链表里,排在第几个元素。

        所以,我们需要用一个结构,将链表节点之间联系起来。

        比较简单地,自定义一个Class,有一个Node和一个int属性,头节点head是0,之后的按顺序排序。

        这里有一个问题:我们可以知道原链表的节点关系,但是无法映射到新链表中。

        解释:新链表是新对象,占用新内存,所以与原节点不能用“==”判同。

        因此,这个Class类,需要有两个Node、一个int属性,与上述类似,不过此时,两个Node,一个存储原链表的节点,另一个存储现在链表的节点。【在后续应用中,甚至不用int属性】

        此时,拷贝random域有方法了。解释:

        我们在浅度拷贝(即没考虑random域)时,将Class类填满。

        然后进行第二次遍历,这次遍历,从head开始,把原链表的每一个节点的random域找到,然后在Class中对应的新Node,即可深度拷贝。

        新问题:这种Class结构,需要花费很多资源,遍历起来也比较麻烦。

        解决方案:用HashMap。

四、解题难点分析

        无。

五、代码【HashMap】

class Solution {public Node copyRandomList(Node head) {// 空节点直接返回if(head == null){return null;}// 存储新、旧节点间关系Map<Node, Node> maps = new HashMap<>();Node temp = head.next;Node res, real;res = new Node(head.val);res.next = head.next;// 浅度拷贝real = res;maps.put(head, res);while(temp!=null){real.next = new Node(temp.val);maps.put(temp, real.next);temp = temp.next;real = real.next;}// 拷贝random域temp = head;real = res;while(temp!=null){if(temp.random != null){// 非空,则通过原链表的random域,映射到新链表的random域real.random = maps.get(temp.random);}temp = temp.next;real = real.next;}return res;}
}

        已经很久没更新百日筑基的内容了,一方面是这段时间忙于实训,需要重新学习、复习很多基础的框架知识,另一方面,算法题的刷题出现了瓶颈,对于回溯算法、贪心算法和图论,我已经觉得有点力不从心,虽然这些题目不难,但是由于自身知识储备不足,学起来比较吃力。

        不过好在,我已经大概刷了60余题,写百日筑基系列的基础,至少也到了下一个月,所以还是不担心缺少内容创作。这段文字写得很乱,也不知道有没有人在看这个系列,不过我会坚持下去的,积累就是人生漫漫长路的解决方案啊。

以上内容即我想分享的关于力扣热题27的一些知识。

        我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/337990.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode - 周赛399

目录 一&#xff0c;3162. 优质数对的总数 I 二&#xff0c;3163. 压缩字符串 III 三&#xff0c;3164. 优质数对的总数 II 四&#xff0c; 3165. 不包含相邻元素的子序列的最大和 一&#xff0c;3162. 优质数对的总数 I 假设 x 是 nums1 数组中的值&#xff0c;y 是 nums2…

WebGL实现医学教学软件

使用WebGL实现医学教学软件是一个复杂但非常有益的项目&#xff0c;可以显著提升医学教育的互动性和效果。以下是详细的实现步骤&#xff0c;包括需求分析、技术选型、开发流程和注意事项。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作…

Python自动实时查询预约网站的剩余名额并在有余额时发邮件提示

本文介绍基于Python语言&#xff0c;自动、定时监测某体检预约网站中指定日期的体检余额&#xff0c;并在有体检余额时自动给自己发送邮件提醒的方法。 来到春招末期&#xff0c;很多单位进入了体检流程。其中&#xff0c;银行&#xff08;尤其是四大行&#xff09;喜欢“海检”…

404.左叶子之和

计算给定二叉树的所有左叶子之和。 示例&#xff1a; 思路&#xff1a; 通过父节点来判断七子节点是不是我们要收集的元素。因为如果遍历到孩子节点&#xff0c;我们无法判断它是左孩子还是右孩子。 后序遍历&#xff0c;左右中。 判断当前节点是不是左叶子是无法判断的&…

33【Aseprite 作图】树——拆解

1 树叶 画树叶真累啊&#xff0c;可以先画一个轮廓&#xff0c;细节一点点修 2 1 2 &#xff1b;2 2 2 &#xff08;横着横&#xff09;&#xff0c;这样一点点画树叶 填充颜色&#xff0c;用了喷雾工具 2 树干部分 轮廓部分&#xff0c;左边的是3 3 3 &#xff1b;上下都是…

【上海大学计算机组成原理实验报告】六、内存系统实验

一、实验目的 学习内存访问机制。理解代码和数据的分区存放原理和技术。 二、实验原理 根据实验指导书的相关内容&#xff0c;地址寄存器MAR用来存放要进行读或写的存储器EM的地址。其内容经数据总线DBUS写入&#xff0c;因此必须在数据总线上具有数据后&#xff0c;配合MAR允…

(奇幻森林)POLYGON - Enchanted Forest - Nature Biomes - 3D Environment Art by Synty

各种雄伟的树木,装饰着优雅简化的树叶,在头顶形成了一个天堂般的树冠,在苔藓覆盖的森林地面上投下了宁静的咒语。 每一项资产,从引人入胜的环境材料到平缓的波浪状山丘,都经过精心制作,将您带到魔法和自然融合的地方。POLYGON-魔法森林-自然生物技术为数字领域注入真正魔…

AI手语研究数据集;视频转视频翻译和风格化功能如黏土动画;AI检测猫咪行为;开放源码的AI驱动搜索引擎Perplexica

✨ 1: Prompt2Sign 多语言手语数据集&#xff0c;便捷高效用于手语研究。 Prompt2Sign 是一个全面的多语言手语数据集&#xff0c;旨在通过工具自动获取和处理网络上的手语视频。该数据集具有高效、轻量的特点&#xff0c;旨在减少先前手语数据集的不足之处。该数据集目前包含…

【qt】多窗口开发

多窗口开发 一.应用场景二.嵌入的窗口1.设计Widget窗口2.创建窗口3.添加窗口4.总代码 三.独立的窗口1.创建窗口2.显示窗口 四.总结 一.应用场景 多窗口,顾名思义,有多个窗口可以供我们进行操作! 截个小图,你应该就知道了 OK,话不多说,直接开干,先来设计我们的主窗口 需要蔬菜…

数据整理的Compact流程 (二)|OceanBase数据转储合并技术解读(二)

上篇文章《数据整理的Compact流程 &#xff08;一&#xff09;&#xff5c;OceanBase数据转储合并技术解读&#xff08;二&#xff09;》中&#xff0c;有讲解到&#xff0c;在OceanBase数据库中&#xff0c;当MemTable写满时&#xff0c;将其下刷到Mini SSTable的过程包含两个…

使用 Django ORM 进行数据库操作

文章目录 创建Django项目和应用定义模型查询数据更新和删除数据总结与进阶聚合和注解跨模型查询原始SQL查询 Django是一个流行的Web应用程序框架&#xff0c;它提供了一个强大且易于使用的对象关系映射&#xff08;ORM&#xff09;工具&#xff0c;用于与数据库进行交互。在本文…

第六届“智能设计+运维”国产工业软件研讨会暨2024年天洑软件用户大会圆满召开

2024年5月23-24日&#xff0c;第六届“智能设计运维”国产工业软件研讨会暨2024年天洑软件用户大会在南京举办。来自国产工业软件研发企业、制造业企业、高校、科研院所的业内大咖&#xff0c;能源动力、船舶海事、车辆运载、航空航天、新能源汽车、动力电池、消费电子、石油石…

CATIA二次开发VBA入门(4)——进程外开发环境搭建,vb.net在Visual Studio中开发,创建圆柱曲面的宏录制到二次开发案例

目录 引出vb.net和vb6.0 进程外开发环境搭建vb.net开发环境搭建《CATIA二次开发技术基础》模板 添加宏库引用 vs开发环境初步vs中的立即窗口对象浏览器 建立模板案例&#xff1a;创建一堆圆柱曲面第一步&#xff1a;录制宏第二步&#xff1a;代码精简第三步&#xff1a;for循环…

IsoBench:多模态基础模型性能的基准测试与优化

随着多模态基础模型的快速发展&#xff0c;如何准确评估这些模型在不同输入模态下的性能成为了一个重要课题。本文提出了IsoBench&#xff0c;一个基准数据集&#xff0c;旨在通过提供多种同构&#xff08;isomorphic&#xff09;表示形式的问题&#xff0c;来测试和评估多模态…

[数据集][目标检测]老鼠检测数据集VOC+YOLO格式4107张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4107 标注数量(xml文件个数)&#xff1a;4107 标注数量(txt文件个数)&#xff1a;4107 标注…

数据结构-堆(带图)详解

前言 本篇博客我们来仔细说一下二叉树顺序存储的堆的结构&#xff0c;我们来看看堆到底如何实现&#xff0c;以及所谓的堆排序到底是什么 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;数据结构_普通young man的博客-CSDN博客 若有问题 评…

小熊家务帮day8-day9 客户管理模块2 (用户定位,地址簿,实名认证,银行卡信息上传等功能)

客户管理模块 0.用户定位功能0.1 需求0.2 接口分析0.3 接口开发Controller层开发Service层开发 1.我的地址簿功能1.1 需求1.2 数据库设计1.3 新增地址簿1.3.1 接口设计1.3.2 接口开发Controller层开发Service层开发测试功能 1.4 地址簿查询1.4.1 接口设计1.4.2 接口开发Control…

五分钟“手撕”栈

实现代码放开头&#xff0c;供大家学习与查阅 目录 一、实现代码 二、什么是栈 三、栈的常见操作 底层实现是链表。 入栈 出栈 四、Stack的使用 五、栈的习题 第一题 第二题 第三题 第四题 第五题 第六题 第七题 六、栈、虚拟机栈、栈帧的区别 目录 一、…

Linux学习笔记(清晰且清爽)

本文首次发布于个人博客 想要获得最佳的阅读体验&#xff08;无广告且清爽&#xff09;&#xff0c;请访问本篇笔记 Linux安装 关于安装这里就不过多介绍了&#xff0c;安装版本是CentOS 7&#xff0c;详情安装步骤见下述博客在VMware中安装CentOS7&#xff08;超详细的图文教…

他人项目二次开发——慎接

接了一个朋友的项目——开发及运营迭代差不多2年多了&#xff0c;整体样子移动端和PC都能正常使用&#xff0c;但后期的扩展性及新功能添加出现瓶颈。 因此给了一部分钱&#xff0c;让我接手来开发——重构架构。 背景说明 朋友公司的技术人员是我帮忙招聘的&#xff0c;相关技…