当前位置: 首页 > news >正文

没有关系的话,那就去建立关系吧

        今天给大家分享一道链表的好题--链表的深度拷贝,学会这道题,你的链表就可以达到优秀的水平了。力扣

         先来理解一下题目意思,即建立一个新的单向链表,里面每个结点的值与对应的原链表相同,并且random指针也要指向新链表中与原链表对应的那个相对位置。(即假设原链表中的第一个结点的random指向原链表的最后一个结点,那么新链表的第一个结点也要指向新链表的最后一个结点,即random指针是链表内部确定相对位置的一个指针)。

        首先,拷贝一个新的链表,其对应结点的值与原链表对应结点的值相同是很容易实现的。可以用一个cur指针遍历原链表,然后建立一个新链表头,然后逐个尾插既可。   

struct Node* cur=head;struct Node* newhead = NULL;struct Node* tail = NULL;while(cur){//每次尾插都需要一个新结点,其val与原链表对应相等struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));//第一次尾插时if(NULL ==tail){newhead = tail =newnode;newnode->val = cur->val;newnode->next = newnode->random = NULL;}//后续尾插else{tail->next = newnode;tail = tail->next;}//拷贝一个新结点后,cur往后走cur = ucr->next;}

此时,只是完成了next链接和val拷贝,random的指向还没有拷贝。

暴力求解O(N^2)

可以建立一个结构体的指针数组   struct Node* arr[n]  n为原链表中的结点数

    struct Node* arr[n];int count = 0;while(cur){arr[count] = cur->random;count++;cur =cur->next;}

再次利用cur遍历原链表,将每个结点的random保存在创建的结构体指针数组 arr中。

struct Node* newcur=newhead;int newcount=-1;while(newcur){++newcount;//每次进来都拿到原链表的一个randomstruct Node* tmp = arr[newcount];//用tmp保存这个randomcur = head;while(cur != tmp){//遍历原链表,看看此时的random是原链表的第几个结点count++;}//找到新链表中对应的第count个结点struct Node* find = newhead;while(count--){//一共走count步newhead = newhead->next;}//找到了newcur位置的random的指向newcur->random = find;//newcur继续往后走newcur = newcur->next;}

暴力解法虽然也能解决问题,但是时间复杂度为O(N^2),效率低,不推荐。

更优解O(N)

        通过暴力解法我们可以发现,寻找random指向的难点在于它是随机的,如果想要确定具体的相对位置(相对于头是第几个)则必须经过2次遍历,那么怎样简化寻找相对位置的过程呢?

        想一下random的关系在哪里出现,应该只有原链表中,而我们又想要建立新链表中random的关系,因此我们必须建立原链表与新链表直接的关系,通过原链表的random找到新链表的random。

        再借助next指针思考,我们可以将新链表对应的结点连接到原链表上。

        

 此时逻辑一下子清晰了,每个新结点都在原对应结点的next位置。

例如:对于13这个结点的random连接,新13->random = 原13->random->next,即通过原链表random的查找方式,再加上next,来连接新链表的random。

具体的实现过程分为3个方面。

1、连接原、新链表

struct Node* cur=head;while(cur){//建立新结点并初始化struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));newnode->next = newnode->random =NULL;random->val = cur->val;//先保存一下原结点的下一个结点struct Node* next = cur->next;//将新结点连接到原链表cur->next = newnode;newnode->next = next;//cur继续往后走cur = next;}

2、建立新链表的random联系

    cur = head;while(cur){//确保cur不为NULL,再建立copy指向cur的nextstruct Node* copy = cur->next;//建立copy的random联系时,要确保其不为空,否则不能进行next操作//因此这里讨论一下原链表的random是否为空if(NULL == cur->random){copy->random = NULL;}else{   copy-> random = cur->random->next;}//连接后cur继续往后走cur = copy->next;}

要注意,copy指针和cur指针移动的位置,可以理解为cur不为空时,建立copy指向此时cur的下一个,完成相关连接后copy丢弃,cur往后走,copy只起到临时变量的作用(连接后便丢弃)。

 

3、分离原、新链表

分离的过程直接将copy部分的结点尾插到一个新结点即可

struct Node* newhead=NULL,*tail=NULL;cur=head;while(cur){struct Node* copy = cur->next;struct Node* next = copy->next;if(NULL == tail)//第一次尾插{newhead = tail =copy;}else//后续尾插{tail->next = copy;//tail往后走,指向新的最后一个结点tail = tail->next;}//分离原链表,cur继续往后走cur->next=next;cur= next;}return newhead;

这部分要注意,else内部tail往下走是后续尾插才有的操作。

 

总结:为了优化代码,使时间复杂度变为O(N),必须建立原来链表的新链表直接的联系,借助原链表的random->next,来连接新链表的random。

所以说,没有关系的话,那就去勇敢的建立关系吧。

 

相关文章:

没有关系的话,那就去建立关系吧

今天给大家分享一道链表的好题--链表的深度拷贝,学会这道题,你的链表就可以达到优秀的水平了。力扣 先来理解一下题目意思,即建立一个新的单向链表,里面每个结点的值与对应的原链表相同,并且random指针也要指向新链表中…...

Vue项目

package.json : 描述这个NPM包的所有相关信息,包括作者、简介、包依赖、构建等信息,格式是严格的JSON格式。和java的maven的pom文件作用一样。 node_modules: 依赖需要下载后才能使用,存在依赖包的地方。使用npm install 安装依赖 babel.co…...

【webrtc】ICE 到VCMPacket的视频内存分配

ice的数据会在DataPacket 构造是进行内存分配和拷贝而后DataPacket 会传递给rtc模块处理rtc模块使用DataPacket 构造rtp包最终会给到OnReceivedPayloadData 进行rtp组帧。吊炸天的是DataPacket 竟然没有声明析构方法。RtpVideoStreamReceiver::OnReceivedPayloadData 的内存是外…...

进阶C语言——指针(二)【题目练习】

文章目录1.指针和数组概念的理解2.指针和数组笔试题解析一维数组字符数组二维数组1.指针和数组概念的理解 指针和数组 数组:能够存放一组相同类型的元素,数组的大小取决于数组的元素个数和元素类型指针:也是地址或指针变量,大小是…...

Ajax简介

Ajax简介和使用 1.简介 AJAX Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。 Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及…...

ChatGPT 4 测试 两数比较大小问题。

按: 上次用3.5 测试了ChatGPT的两数比较大小问题,结果失败了。我要求不能用if语句,它避免不了。这次终于成功了,看来是进步很大。对话记录如下(英文) MaraSun Compare two 2 numbers in C# , but IF is no…...

SSM-CRUD整合视频教程:Spring、SpringMVC、MyBatis、bootstrap、pagehelper、JSR303后端校验

1、项目说明 1.1、业务说明 SSM:SpringMVCSpringMyBatisCRUD: Create(创建)Retrieve(查询)Update(更新)Delete(删除) 总结:通过SSM框架来完成一个CRUD的操作。 1.2、功…...

Linux常用命令——基于Ubuntu22.04

本文介绍了一些Linux的常用命令。为了便于快速检索命令位置,文章二级标题都以“命令:命令的作用”展示,有些命令会先介绍命令的几个常用参数,然后结合具体的操作展示命令的使用。为了便于记忆,也会提到命令是由哪些短语…...

Sentinel

SentinelSentinel介绍什么是Sentinel?为什么需要流量控制?为什么需要熔断降级?一些普遍的使用场景本文介绍参考:Sentinel官网《Spring Cloud Alibaba 从入门到实战.pdf》Sentinel下载/安装项目演示构建项目控制台概览演示之前需先明确&#…...

再也不想去字节跳动面试了,6年测开面试遭到这样打击.....

前几天我朋友跟我吐苦水,这波面试又把他打击到了,做了快6年软件测试员。。。为了进大厂,也花了很多时间和精力在面试准备上,也刷了很多题。但题刷多了之后有点怀疑人生,不知道刷的这些题在之后的工作中能不能用到&…...

【深度解刨C语言】符号篇(全)

文章目录一.注释二.续行符与转义符1.续行符2.转义符三.回车与换行四.逻辑操作符五.位操作符和移位操作符六.前置与后置七.字符与字符串八./和%1.四种取整方式2.取模与取余的区别和联系3./两边异号的情况1.左正右负2.左负右正九.运算符的优先级一.注释 注释的两种符号&#xff…...

VS Code 将推出更多 AI 功能给 Java 开发者

大家好,欢迎来到我们的二月更新!我们将为您带来与 JUnit 5 并行测试相关的新功能以及用于 Spring Boot Dashboard 的过滤功能。另外,OpenAI 和 ChatGPT 是最近的热点,所以在 GitHub Copilot 方面也有一些令人激动的消息&#xff0…...

关于利用FFT分析时域信号幅相的思考与验证

引言 利用FFT分析/估计时域信号的幅度和相位,属于传统估计的范畴。估计的准确程度受频率分辨率的影响较大。如果被估计的目标频率等于频率分辨率的整数倍,信号的幅相估计都是最准确的。一旦目标频率不等于频率分辨率的整数倍,幅度估计值将会…...

基于java中的Springboot框架实现餐厅点餐系统展示

基于java中的Springboot框架实现餐厅点餐系统开发语言和工具 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 21世纪的今天,随着社会的不断发展与进步,人们对…...

案例07-在线人员列表逻辑混乱

一、背景介绍 在线人员列表涉及到的问题: 类中写了公共变量最后导致数据混乱现象 保存数据没有考虑业务的隔夜覆盖导致的逻辑漏洞 涉及到继承,对于this,如果父类有同样的成员最终使用哪一个? 参数不一致导致后续维护混乱 mysql由…...

Java集合框架

Java集合框架是Java编程语言所提供的一种便捷的数据结构的实现。Java集合框架提供了一种统一的接口和机制来访问和操作集合中的元素,这些元素可以是对象、基本数据类型或其他集合。Java集合框架是Java应用程序中最常用的特性之一,它为开发人员提供了许多…...

奇异值分解(SVD)原理与在降维中的应用

奇异值分解(SVD)原理与在降维中的应用 奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域。是很多机器学习算…...

GDB调试程序

1.GDB 调试程序 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。在UNIX平台下做软件,GDB这个调试工具有比VC的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。 一般来说,GDB主要帮忙你完成下面四个方面的功能…...

五种IO模型

用户空间与内核空间 操作系统把内存空间划分成了两个部分:内核空间和用户空间。 为了保护内核空间的安全,操作系统一般都限制用户进程直接操作内核。 所以,当我们使用TCP发送数据的时候,需要先将数据从用户空间拷贝到内核空间&a…...

5 全面认识java的控制流程

全面认识java控制流程1.块作用域2.条件语句3.迭代语句3.1while语句3.2do-while语句3.3for语句3.4 for-in语法4.中断控制流程的语句4.1 return4.2 break和continue4.2.1 不带标签的break语句4.2.2 带标签的break语句4.2.3 continue语句4.3 goto()5.多重选择:switch语句1.块作用域…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...