随机链表的复制[中等]

优质博文:IT-BLOG-CN

一、题目

给你一个长度为n的链表,每个节点包含一个额外增加的随机指针random,该指针可以指向链表中的任何节点或空节点。构造这个链表的深拷贝。深拷贝应该正好由n个全新节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的next指针和random指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点。

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

用一个由n个节点组成的链表来表示输入/输出中的链表。每个节点用一个[val, random_index]表示:
【1】val:一个表示Node.val的整数。
【2】random_index:随机指针指向的节点索引(范围从0n-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
-104 <= Node.val <= 104
Node.randomnull或指向链表中的节点。

二、代码

【1】回溯 + 哈希表: 本题要求我们对一个特殊的链表进行深拷贝。如果是普通链表,我们可以直接按照遍历的顺序创建链表节点。而本题中因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建,因此我们需要变换思路。一个可行方案是,我们利用回溯的方式,让每个节点的拷贝操作相互独立。对于当前节点,我们首先要进行拷贝,然后我们进行「当前节点的后继节点」和「当前节点的随机指针指向的节点」拷贝,拷贝完成后将创建的新节点的指针返回,即可完成当前节点的两指针的赋值。

具体地,我们用哈希表记录每一个节点对应新节点的创建情况。遍历该链表的过程中,我们检查「当前节点的后继节点」和「当前节点的随机指针指向的节点」的创建情况。如果这两个节点中的任何一个节点的新节点没有被创建,我们都立刻递归地进行创建。当我们拷贝完成,回溯到当前层时,我们即可完成当前节点的指针赋值。注意一个节点可能被多个其他节点指向,因此我们可能递归地多次尝试拷贝某个节点,为了防止重复拷贝,我们需要首先检查当前节点是否被拷贝过,如果已经拷贝过,我们可以直接从哈希表中取出拷贝后的节点的指针并返回即可。

在实际代码中,我们需要特别判断给定节点为空节点的情况。

class Solution {Map<Node, Node> cachedNode = new HashMap<Node, Node>();public Node copyRandomList(Node head) {if (head == null) {return null;}if (!cachedNode.containsKey(head)) {Node headNew = new Node(head.val);cachedNode.put(head, headNew);headNew.next = copyRandomList(head.next);headNew.random = copyRandomList(head.random);}return cachedNode.get(head);}
}

时间复杂度: O(n),其中n是链表的长度。对于每个节点,我们至多访问其「后继节点」和「随机指针指向的节点」各一次,均摊每个点至多被访问两次。
空间复杂度: O(n),其中n是链表的长度。为哈希表的空间开销。

【2】迭代 + 节点拆分: 注意到方法一需要使用哈希表记录每一个节点对应新节点的创建情况,而我们可以使用一个小技巧来省去哈希表的空间。

我们首先将该链表中每一个节点拆分为两个相连的节点,例如对于链表A→B→C,我们可以将其拆分为A→A′→B→B′→C→C′。对于任意一个原节点S,其拷贝节点S′即为其后继节点。这样,我们可以直接找到每一个拷贝节点S′的随机指针应当指向的节点,即为其原节点S的随机指针指向的节点T的后继节点T′。需要注意原节点的随机指针可能为空,我们需要特别判断这种情况。

当我们完成了拷贝节点的随机指针的赋值,我们只需要将这个链表按照原节点与拷贝节点的种类进行拆分即可,只需要遍历一次。同样需要注意最后一个拷贝节点的后继节点为空,我们需要特别判断这种情况。

class Solution {public Node copyRandomList(Node head) {if (head == null) {return null;}for (Node node = head; node != null; node = node.next.next) {Node nodeNew = new Node(node.val);nodeNew.next = node.next;node.next = nodeNew;}for (Node node = head; node != null; node = node.next.next) {Node nodeNew = node.next;nodeNew.random = (node.random != null) ? node.random.next : null;}Node headNew = head.next;for (Node node = head; node != null; node = node.next) {Node nodeNew = node.next;node.next = node.next.next;nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;}return headNew;}
}

时间复杂度: O(n),其中n是链表的长度。我们只需要遍历该链表三次。读者们也可以自行尝试在计算拷贝节点的随机指针的同时计算其后继指针,这样只需要遍历两次。
空间复杂度: O(1)。注意返回值不计入空间复杂度。

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

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

相关文章

Hadoop学习笔记(HDP)-Part.18 安装Flink

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

sort by modulus of a complex number

描述 复数E包含实部x和虚部y, Exyi;E的模为: 输入n(<1000)和n对(x,y); 按模数升序对复合体进行排序&#xff0c;如果模数相等&#xff0c;则按输入顺序排序。 排序后输出n行of (x_i,y_i,mod_i)&#xff0c;保留2个十进制小数。 输入 输入n和n对(x,y); 输出 输出排序后的n行(…

P=NP?

背景&#xff1a;   2000年5月24日&#xff0c;新罕布什尔州的克莱数学研究所列出了数学和计算机科学中七个未解决的问题。然而&#xff0c;直到今天&#xff0c;这些问题中只有一个被解决了&#xff0c;那就是庞加莱猜想&#xff08;Poincar Conjecture&#xff09;——被俄…

手机如何设置防骚扰电话?

很多人都曾接到过烦人的推销电话&#xff0c;这些电话不仅让人感到烦恼&#xff0c;而且有时候还会接二连三地打来&#xff0c;让人不胜其烦。我们的手机号码似乎已经被泄露&#xff0c;很难避免这些骚扰。 有时&#xff0c;我们因无法忍受骚扰电话而选择立即将其拉黑&#xff…

考研数据结构

851专业课 线性表线性表的定义线性表的顺序表示顺序表代码 线性表的链式存储表示单链表代码 顺序表和链表的比较 栈和队列栈顺序栈链栈 队列顺序队列链队列 串和数组kmp数组广义表 树和二叉树二叉树二叉树代码 线索二叉树线索二叉树代码 树和森林树的存储结构 哈夫曼树 图图的存…

【原创】提升MybatisPlus分页便捷性,制作一个属于自己的分页插件,让代码更加优雅

前言 MybatisPlus的分页插件有一点非常不好&#xff0c;就是要传入一个IPage&#xff0c;别看这个IPage没什么大不了的&#xff0c;最多多写一两行代码&#xff0c;可这带来一个问题&#xff0c;即使用xml的查询没法直接取对象里面变量的值了&#xff0c;得Param指定xml中的变…

探索Selenium的规避检测策略

Selenium之规避检测 背景 ​ 目前很多大网站有对selenium采取了监测机制。在正常情况下我们用浏览器访问相关网站的window.navigator.webdriver的值为 undefined或者为false。而使用selenium访问则该值为true。我们如何伪装&#xff0c;防止被检测出来呢&#xff1f; ​ 这是…

POJ 3233 Matrix Power Series 动态规划(矩阵的幂)

一、题目大意 给出一个矩阵A&#xff0c; 输出矩阵B的每一项对M取余数的值。 二、解题思路 以二维矩阵为例&#xff0c;首先计算K2的情况&#xff0c;我们设结果矩阵为B 有如下表达式 那么不难看出&#xff0c;需要的矩阵其实就是以下的两个矩阵相乘后的左上角的N*N个 然后…

初识Linux——基本指令(详解)1

呀哈喽&#xff0c;我是结衣。 在学习数据结构的同时&#xff0c;也不要忘了Linux的学习啊。今天我们开始Linux的教学&#xff0c;在学习之前我们肯定要会搭建Linux的学习环境&#xff0c;在我们的以前的博客里是有讲解的&#xff0c;所以所以这里我们就不在多说&#xff0c;我…

UDP数据报套接字

文章目录 DatagramSocket APIDatagramPacket API示例一: 请求响应UDP服务端UDP客户端 DatagramSocket API Socket是操作系统中的一个概念&#xff0c;本质上是一种特殊的文件&#xff0c;Socket就属于把“网卡”这个设备给抽象成了文件。往 Socket 文件中写数据&#xff0c;就…

深入探讨Guava的缓存机制

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;今天咱们聊聊Google Guava的缓存机制。缓存在现代编程中的作用非常大&#xff0c;它能提高应用性能&#xff0c;减少数据库压力&#xff0c;简直就是性能优化的利器。而Guava提供的缓存功能&#xff0c;不仅强大…

iptables入门

今天我的工作遇到了巡检网络配置的任务&#xff0c;这次巡检的主机都是运行十多年的机器&#xff0c;并不是新的firewalld&#xff0c;基本都是iptables&#xff0c;上学的时候以为这些都没人用&#xff0c;所以没有认真学习&#xff0c;现在需要用到了&#xff0c;所以写一篇文…

PostGIS学习教程九:空间连接

PostGIS学习教程九&#xff1a;空间连接 空间连接&#xff08;spatial joins&#xff09;是空间数据库的主要组成部分&#xff0c;它们允许你使用空间关系作为连接键&#xff08;join key&#xff09;来连接来自不同数据表的信息。我们认为“标准GIS分析”的大部分内容可以表示…

17.认识下Docker之docker的核心原理(2)

1.容器-我的小世界 不知道大家看没看过小说《完美时间》&#xff0c;里面石昊经常进入一个小世界在里面与世隔绝的修炼或者战斗&#xff0c;总之就是在一个完全封闭的空间里做他想做的事情而与外界隔离&#xff0c;不受侵扰。通过前面的分析我们知道&#xff0c;Namepace让应用…

SringBoot的启动原理,保姆级带你认识,让面试管对你刮目相看

SringBoot的启动原理&#xff0c;保姆级带你认识&#xff0c;让面试管对你刮目相看 一&#xff0c;介绍 graph TD; A[启动类] --> B[SpringApplication.run()] B --> C[创建SpringApplication实例] C --> D[初始化应用上下文] D --> E[加载应用配置] E --> F[…

树_二叉搜索树累加求和

//给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值等于原树中大于或等于 // node.val 的值之和。 // // 提醒一下&#xff0c;二叉搜索树满足下列约束…

【Vulnhub 靶场】【hacksudo: FOG】【简单 - 中等】【20210514】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/hacksudo-fog,697/ 靶场下载&#xff1a;https://download.vulnhub.com/hacksudo/hacksudo-FOG.zip 靶场难度&#xff1a;简单 - 中等 发布日期&#xff1a;2021年05月14日 文件大小&#xff1a;1.3 GB 靶场作…

解决 vite 中 import.meta.globEager is not function 的问题

本人正在重构两年前搭建到一半的博客网站&#xff0c;相关依赖都很陈旧&#xff0c;用到了 npm-check-updates 检测项目可升级依赖&#xff1a; 升级完成后解决完依赖发现控制台报错 import.meta.globEager is not function解决方案&#xff1a; vite版本降至4.3.0 亲测有效&…

忽略python运行出现的大量警告

添加以下代码即可 import warnings warnings.filterwarnings(ignore)

App内存优化

一、内存优化介绍 1.背景介绍 内存是大问题但缺乏关注压实骆驼的最后一个稻草&#xff08;堆栈溢出&#xff09; 2.内存问题 内存抖动&#xff1a;锯齿状、GC导致卡顿内存泄露&#xff1a;可用内存减少、频繁GC内存溢出&#xff1a;OOM&#xff0c;程序异常 二、优化工具选…