算法题解记录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.mzph.cn/web/20399.shtml

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

相关文章

Flutter开发指南

Flutter开发指南&#xff08;Android 开发角度&#xff09; 与Android 的对比 1.Android 的View 与Flutter 的对应关系&#xff1a; a.在android 中&#xff0c;view 是屏幕显示的基础&#xff0c;比如 button&#xff0c;文本&#xff0c;列表&#xff0c;输入框都是 view。…

小柴带你学AutoSar系列一、基础知识篇(4)编译

小柴带你学AutoSar总目录https://blog.csdn.net/qianshang52013/article/details/138140235?spm1001.2014.3001.5501 Flechazohttps://www.zhihu.com/people/jiu_sheng 编译真的很重要&#xff01;了解一下机器是如何工作的吧。当然啦&#xff01;通过学习这篇文章还可以学习…

unityBIM

Revit模型到Unity勉强能用 1、Revit直接导出FBX&#xff0c;然后拖到unity里面 2、通过Navisworks导出FBX&#xff0c;拖到unity里面。 我什么都还没做&#xff0c;只建立了一个空的URP效果&#xff0c;把FBX拖进去&#xff0c;挂了一个相机控制器&#xff0c;效果勉强看得过…

中医的悠久历史文化

中医&#xff0c;作为中华民族的传统医学&#xff0c;拥有着悠久的历史和深厚的文化底蕴。自古以来&#xff0c;中医便以其独特的理论体系和治疗方法&#xff0c;为中华民族的繁衍昌盛做出了巨大贡献。如今&#xff0c;随着现代医学的不断发展&#xff0c;中医依然以其独特的魅…

APP上架 篇三:ICP备案

文章目录 系列文章ICP备案简介非经营性备案与经营性备案ICP备案官网ICP备案流程ICP备案实例(阿里云服务器+新网域名)ICP备案费用ICP许可证的流程和费用系列文章 APP上架 篇一:上架资质要求 APP上架 篇二:注册域名 APP上架 篇三:ICP备案 系列计划预告: APP上架 篇二:计…

奇安信_NAC终端安全准入系统(相关问题整理)

奇安信终端安全准入系统 ,下称NAC 一、入网控制方式 1.IP流量控制 2.802.1X 准入 需要NAC、交换机、终端 以802.1X 3.DHCP 准入 将NAC作为DHCP服务器&#xff0c;为客户端分配地址&#xff0c;并对分配地址的客户端进行入网管控。 &#xff08;*&#xff09;可选 强制入网…

【计算机毕设】SpringBoot海滨体育馆管理系统设计与实现 - 源码免费(私信领取)

免费领取源码 &#xff5c; 项目完整可运行 &#xff5c; v&#xff1a;chengn7890 诚招源码校园代理&#xff01; 1. 引言 体育馆作为重要的体育场馆&#xff0c;承担着举办体育赛事、健身活动和文化演出等多种功能。为了提高体育馆的管理效率和服务质量&#xff0c;本项目旨在…

DASK==python并行计算

文档10 Minutes to Dask — Dask documentation demo代码 import numpy as np import pandas as pd import dask.dataframe as dd import dask# 设置调度器为多线程 dask.config.set(schedulerthreads) # 创建一个示例的Pandas DataFrame index pd.date_range("2021-09…

SpringBoot轻松解决Excel导入导出功能

前言 在日常的开发工作中&#xff0c;Excel 文件的读取和写入是非常常见的需求&#xff0c;特别是在后台管理系统中更为频繁&#xff0c;基于传统的方式操作excel通常比较繁琐&#xff0c;EasyExcel 库的出现为我们带来了更简单、更高效的解决方案。本文将介绍 EasyExcel 库的…

Linux C/C++ main函数

main函数有三个参数&#xff1a;argc、argv、envp int main(int argc,char*argv[],char*envp) {return 0; } //argc 存放了程序参数个数&#xff0c;包括程序本身 //argv 字符串数组&#xff0c;存放了每个参数的值&#xff0c;包括程序本身 //envp 字符串数组&#xff0c;存放…

Java后端代码框架包设计-什么是Domain,BO,VO?我们改如何区分和定义?

我们先来看看一个项目的代码结构,如下图: 1.定义包名用domain这个单词是什么含义 在Java中,domain 这个单词通常用于表示应用程序的“领域模型”(Domain Model)或“领域层”(Domain Layer)。领域模型是描述系统业务逻辑和规则的对象集合,它通常包含实体(Entities)、…

主机加固解决方案分享

在信息化社会的今天&#xff0c;网络安全问题日益凸显&#xff0c;其中主机的安全性更是至关重要。主机加固&#xff0c;作为提升计算机系统安全性的重要手段&#xff0c;其重要性不言而喻。那么&#xff0c;有什么好的方案呢&#xff1f;今天我就给大家介绍个主机加固的解决方…

Git使用规范及命令

文章目录 一、Git工作流二、分支管理三、Git命令操作规范1. 切到develop分支&#xff0c;更新develop最新代码2. 新建feature分支&#xff0c;开发新功能3. 完成feature分支&#xff0c;合并到develop分支4. 当某个版本所有的 feature 分支均合并到 develop 分支&#xff0c;就…

领域建模(系统操作复习)

习题 问题 考察点 领域建模 识别概念类 固定模板 Conceptual Class Category Examples specifications,designs, or descriptions of things roles of people containers of other things things in a container abstract noun concepts organizations events processes (…

【代码随想录算法训练Day24】LeetCode 77.组合

Day24 回溯 回溯算法的模板&#xff1a; 回溯函数模板返回值以及参数回溯函数终止条件回溯搜索的遍历过程 LeetCode 77.组合 回溯的经典问题&#xff0c;在每个路径数组中存入下一个数&#xff0c;再接着递归处理路径中的下一个数。 class Solution { public:vector<ve…

vs2022 MSVC2017_64 调试Qt5.14.2源码

pdb调试文件下载路径https://download.qt.io/online/qtsdkrepository/windows_x86/desktop/qt5_5142/qt.qt5.5142.debug_info.win64_msvc2017_64/ 在vs中添加pdb文件符号路径&#xff0c;使其qt在调试时能查找到相应的符号文件。 在需要调试的解决方案下通过解决方案点击&…

【Linux】日志管理

一、日志进程 1、处理日志的进程 rsyslogd&#xff1a;系统专职日志程序 观察rsyslogd程序&#xff1a; ps aux | grep rsyslogd 2、常见的日志文件 1、系统主日志文件: /var/log/messages 动态查看日志文件尾部&#xff1a; tail -f /var/log/messages 2、安全…

背包问题汇总(01背包、完全背包、多重背包、分组背包)

背包问题 01 背包完全背包多重背包分组背包 01 背包 有 n 件物品&#xff0c;每个物品只能使用一次&#xff0c;在不超过背包体积的情况下&#xff0c;总价值最大是多少&#xff1f; #include <iostream> using namespace std; const int N 1010; int n, m; int v[N],…

C语言-01_HelloWord

文章目录 1.C程序运行机制2.HelloWorld的剖析① main()② 函数体③ printf()④ 标准库、头文件 3.输出3.1 printf()标准格式3.2 占位符3.3 输出格式 1.C程序运行机制 过程1&#xff1a;编辑 编写C语言源程序代码&#xff0c;并已文件的形式存储到磁盘中。源程序文件以“.c”作…

Java复数计算

复数在数学、科学或者工程领域是很常用的&#xff0c;可以通过调用Apache Commons Math库来完成&#xff0c;也可以自己手撸。 一、使用Apache Commons Math库 这个库有多个版本&#xff0c;在写这篇文章时&#xff0c;它的最新版是2022年12月19日的4.0-beta1&#xff0c;构建…