力扣OJ题——随机链表的复制

题目:

138. 随机链表的复制

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

要求:构造这个链表的 深拷贝

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

注意:复制链表中的指针都不应指向原链表中的节点 

示例:

思路一:暴力求解

1.拷贝链表

2.处理拷贝链表每个节点的random指针,这里封装一个函数来实现~

通过分析,思路一的时间复杂度应该是O(N^2),这是一种很直观的思路,下面我们来实现

1.拷贝链表,代码如下:

struct Node *copy = (struct Node*)malloc(sizeof(struct Node)),*p;p = copy;struct Node *cur = head;//cur指向原链表的头节点while(cur!=NULL){struct Node *curcopy=(struct Node*)malloc(sizeof(struct Node));curcopy->val=cur->val;curcopy->random=NULL;copy->next=curcopy;//copy是curcopy的前驱,起着拷贝链表的连接作用copy = copy->next;//copy往后走cur=cur->next;//cur往后走}copy->next=NULL;//当cur = NULL后的处理

2.处理拷贝链表每个节点的random指针,代码如下:

cur=head;//让在第一步使用过的cur回到原链表的头copy=p->next;//让在第一步使用过的copy来到拷贝链表的头while(cur!=NULL){if(cur->random==NULL){copy->random=NULL;}else{//find函数是用来找到random指向的节点copy->random=find(head,p->next,cur->random);}copy=copy->next;cur=cur->next;}

find函数的实现代码如下:


//find函数找到random指向的节点//head为原链表的头,copy为拷贝链表的头,dest为目标
struct Node* find(struct Node* head,struct Node* copy,struct Node* dest)
{while(head!=dest){head=head->next;copy=copy->next;}return copy;
}

下面我们将第一步与第二步的代码整合起来,就形成完整的代码

struct Node* find(struct Node* head,struct Node* copy,struct Node* dest);
struct Node* copyRandomList(struct Node* head){if(head == NULL) return NULL;struct Node *copy = (struct Node*)malloc(sizeof(struct Node)),*p;p = copy;struct Node *cur = head;while(cur!=NULL){struct Node *curcopy=(struct Node*)malloc(sizeof(struct Node));curcopy->val=cur->val;curcopy->random=NULL;copy->next=curcopy;copy = copy->next;cur=cur->next;}copy->next=NULL;cur=head;copy=p->next;while(cur!=NULL){if(cur->random==NULL){copy->random=NULL;}else{copy->random=find(head,p->next,cur->random);}copy=copy->next;cur=cur->next;}return p->next;//返回拷贝链表的头
}//find函数找到random指向的节点
struct Node* find(struct Node* head,struct Node* copy,struct Node* dest)
{while(head!=dest){head=head->next;copy=copy->next;}return copy;
}

虽然时间复杂度为O(N^2),但力扣居然给过了

不过这里要说的是,这样暴力的思路往往不是面试官心中的答案,所以下面我们来看一下更优的思路二

思路二:

1.插入拷贝节点在原节点的后面

2.控制拷贝节点的random

   copy -> random = cur ->random->next(这句是精华)

3.解下拷贝节点,同时恢复原链表的指向

思路二的巧妙就在于它在建立拷贝链表时就和原链表有了联系,有了这种联系,之后处理random指针就能更高效,直接就能找到、、

我们看一下思路二的时间复杂度,已经变成了O(N),这就非常的nice

下面我们就来实现这个思路

第一步:插入拷贝节点在原节点的后面,代码如下

    struct Node* cur = head;//cur在原节点的头while (cur != NULL)//第一步{struct Node* copy = (struct Node*)malloc(sizeof(struct Node));copy->val = cur->val;//插入copy->next = cur->next;cur->next = copy;//继续往下cur = copy->next;}

第二步:控制拷贝节点的random,代码如下

    cur = head;//恢复cur到原节点的头while (cur != NULL) //第二步{struct Node* curcopy =  cur->next;//拷贝节点if (cur->random == NULL)  curcopy->random = NULL;elsecurcopy->random =cur->random->next;cur = curcopy->next;}

第三步:解下拷贝节点使其成为独立的链表,同时恢复原链表的指向,代码如下

     cur = head;//恢复cur到原节点的头//第三步struct Node* copyhead=NULL,*copytail=NULL;//定义拷贝链表的头和尾while (cur != NULL){struct Node* curcopy = cur->next;struct Node* curnext = curcopy->next;// curnext是原链表cur的下一个节点//通过尾插使拷贝节点成为独立的链表if(copyhead == NULL)//处理头copyhead = copytail = curcopy;else //处理其他情况{copytail->next = curcopy;copytail = copytail->next;}cur->next= curnext;//恢复原链表的指向cur = curnext;//cur往后走}

下面我们将这三步的代码整合起来,就形成完整的代码

struct Node* copyRandomList(struct Node* head){if  (head == NULL)   return NULL;struct Node* cur = head;//cur在原节点的头while (cur != NULL)//第一步{struct Node* copy = (struct Node*)malloc(sizeof(struct Node));copy->val = cur->val;//插入copy->next = cur->next;cur->next = copy;//继续往下cur = copy->next;}cur = head;//恢复cur到原节点的头while (cur != NULL) //第二步{struct Node* curcopy =  cur->next;//拷贝节点if (cur->random == NULL)  curcopy->random = NULL;elsecurcopy->random =cur->random->next;cur = curcopy->next;}cur = head;//第三步struct Node* copyhead=NULL,*copytail=NULL;while (cur != NULL){struct Node* curcopy = cur->next;struct Node* curnext = curcopy->next;// curnext是原链表cur的下一个节点if(copyhead == NULL)copyhead = copytail = curcopy;else {copytail->next = curcopy;copytail = copytail->next;}cur->next= curnext;//恢复原链表cur = curnext;}return copyhead;//返回拷贝链表的头
}

代码走起来

就过了

好啦,到此为止,今天的随机链表的复制问题就结束啦,如果文中分析,题解代码有不足的地方欢迎大家在评论区讨论和指正

让我们在接下来的时间里一起学习,一起进步吧~

c0fe1378f4b1464abb37998a472b5961.jpg

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

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

相关文章

Vue状态管理库-Pinia

一、Pinia是什么? Pinia 是 Vue 的专属状态管理库,它允许支持跨组件或页面共享状态,即共享数据,他的初始设计目的是设计一个支持组合式API的 Vue 状态管理库(因为vue3一个很大的改变就是组合式API),当然这…

简介高效的 CV 入门指南: 100 行实现 InceptionResNet 图像分类

简介高效的 CV 入门指南: 100 行实现 InceptionResNet 图像分类 概述InceptionResNetInception 网络基本原理关键特征 ResNet 网络深度学习早期问题残差学习 InceptionResNet 网络InceptionResNet v1InceptionResNet v2改进的 Inception 模块更有效的残差连接设计 100 行实现 I…

Docker本地部署Rss订阅工具并实现公网远程访问

文章目录 1. Docker 安装2. Docker 部署Rsshub3. 本地访问Rsshub4. Linux安装Cpolar5. 配置公网地址6. 远程访问Rsshub7. 固定Cpolar公网地址8. 固定地址访问 Rsshub是一个开源、简单易用、易于扩展的RSS生成器,它可以为各种内容生成RSS订阅源。 Rsshub借助于开源社…

JDBC简介

JDBC体系结构 Java Data Base Connectivity(JDBC),Java数据库连接。 JDBC重要的类和接口 JDBC API 定义了一组用于与数据库进行通信的接口和类,这些接口和类都定义在Java.sql包中。 类或接口作用DriverManager处理驱动程序的加…

校园兼职|大学生校园兼职小程序|基于微信小程序的大学生校园兼职系统设计与实现(源码+数据库+文档)

大学生校园兼职小程序目录 目录 基于微信小程序的大学生校园兼职系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户​微信端功能模块​ 2、管理员服务端功能模块 (1) 兼职管理 (2)论坛管理 (3&…

Leetcode 102.二叉树的层序遍历

目录 题目 思路 题目 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]]示例…

leetcode hot100组合综合四

本题中,是要求nums中求的总和为target的排列数,因为题中说了,元素顺序不同,则可以视为不同的结果之一。 所以,根据对背包问题的总结,本题中元素可以重复使用,是完全背包并且需要求排列数&#…

Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录 一、介绍二、方案介绍三、Redis Docker部署四、SpringBoot3 Base代码1. 依赖配置2. 基本代码 五、缓存优化代码1. 校验机制2. 布隆过滤器3. 逻辑优化 一、介绍 当一种请求,总是能越过缓存,调用数据库,就是缓存穿透。 比如当请求一…

数字之美:探索人工智能绘画的奇妙世界

目录 引言AI绘画的定义与发展历程定义与发展历程AI绘画产品有哪些? AI绘画的应用领域设计与创意产业影视与游戏制作数字艺术与展览 AI绘画的基本原理与技术深度学习与神经网络生成对抗网络(GAN)风格迁移算法 AI绘画效果展示一只带着墨镜的小猫在高楼林立…

05.STLvector、list、stack、queue

STL标准模板库 standard template library STL将原来常用的容器和操作进行封装,增加了C的编码效率 容器 string #include vector #include list #include stack #include queue #include set #include map #include 迭代器 容器和算法之间的粘合剂&#xff0…

【ACM出版】第五届计算机信息和大数据应用国际学术会议(CIBDA 2024)

第五届计算机信息和大数据应用国际学术会议(CIBDA 2024) 2024 5th International Conference on Computer Information and Big Data Applications 重要信息 大会官网:www.ic-cibda.org 大会时间:2024年3月22-24日 大会地点&#…

【JavaEE】_form表单构造HTTP请求

目录 1. form表单的格式 1.1 form表单的常用属性 1.2 form表单的常用搭配标签:input 2. form表单构造GET请求实例 3. form表单构造POST请求实例 4. form表单构造法的缺陷 对于客户端浏览器,以下操作即构造了HTTP请求: 1. 直接在浏览器…

01_02_mysql06_(视图-存储过程-函数(变量、流程控制与游标)-触发器)

视图 使用 视图一方面可以帮我们使用表的一部分而不是所有的表,另一方面也可以针对不同的用户制定不同的查询视图。比如,针对一个公司的销售人员,我们只想给他看部分数据,而某些特殊的数据,比如采购的价格&#xff0…

【web安全】渗透测试实战思路

步骤一:选目标 1. 不建议太小的公司(可能都是请别人来开发的,用现成成熟的框架) 2. 不建议一线大厂:腾讯,字节,阿里等,你懂的 3. 不建议政府部门,安全设备多&#xff…

线性代数:线性方程组解的结构

目录 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3

从kafka如何保证数据一致性看通常数据一致性设计

一、前言 在数据库系统中有个概念叫事务,事务的作用是为了保证数据的一致性,意思是要么数据成功,要么数据失败,不存在数据操作了一半的情况,这就是数据的一致性。在很多系统或者组件中,很多场景都需要保证…

开源LLMs导览:工作原理、顶级LLM列表对比

目录 一、开源 LLM 是什么意思?二、开源LLM如何工作?2.1 预训练2.2 代币化2.3 开源LLM的微调2.4 输入编码2.5 训练与优化2.6 推理 三、开源LLM对组织的好处3.1 增强的数据安全和隐私3.2 节约成本3.3 减少供应商依赖性3.4 代码透明度 四、哪种LLM模式最好…

51_蓝桥杯_独立按键

一 电路 注意:J5跳帽接到2~3引脚,使按键S4-S5四个按键的另外一端接地,从而成为4个独立按键。 二 独立按键工作原理 三 代码 代码1:按下S7点亮L1指示灯,松开按键,指示灯熄灭,按下S6点亮L2指示灯…

18.贪心算法

排序贪心 区间贪心 删数贪心 统计二进制下有多少1 int Getbit_1(int n){int cnt0;while(n){nn&(n-1);cnt;}return cnt; }暴力加一维前缀和优化 #include <iostream> #include <climits> using namespace std; #define int long long const int N2e510; in…

three.js 3D可视化地图

threejs地图 可视化地图——three.js实现 this.provinceInfo document.getElementById(provinceInfo); // 渲染器 this.renderer new THREE.WebGLRenderer({antialias: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.container.appendChild…