数据结构每日亿题(四)

news2024/11/25 1:07:19

复制带随机指针的链表

原题传送门:力扣
题目:
在这里插入图片描述这题的大概意思就是:
有这样一个链表,他比普通的链表多一个成员变量:random指针,这个random指针指向的是这个链表中随机一个地方,这个地方是其它节点的位置或者是空指针。现在题目的要求是让你把这个链表复制出来。

一.大概思路

这题的难点主要就是这个随机指针因为这是没有规律的可能这个链表的第一个节点指向第二个节点,但是另一个节点可能指向的就是第三个节点。
虽然这题可以用暴力方法来求解:就是先遍历第一遍找到第一个节点指向的位置在复制时把这个位置写出来,然后在遍历第二遍,第三遍…。这方法可以是可以但是时间复杂度是O(N^2),太多了,可以用但是不推荐。

接下来我来讲一个特别神奇的思路:

第一步

在这里插入图片描述先随便拿个链表做说明,我们在每个节点的后面添加一个新的节点,这个新的节点的里的值和它上个节点的值是一样的:
在这里插入图片描述像这样都连起来了,但是新节点的random还没有设置,接下来就是这个思路的厉害之处。

第二步

在这里插入图片描述先定义两个指针cur,next,我们虽然不知道新节点的random是指向哪里,但是我们直到原来节点的random指向哪里。我们先看第一个原节点的random指向的是NULL,现在我们把这种情况当成一种特殊情况,就是先判断原节点指向的是不是空,是的话新节点的random也指向空。

然后在判断其它情况,这里让cur,next设置好一个新节点的random后往后跳一步:
在这里插入图片描述我们注意看原节点13的random指向的应该是7这个节点,所以说现在我们希望next指向的这个新节点的random也指向新节点的7,但是我们有没有发现我们希望找到的位置就在原来7这个节点的后一步。
用代码来说:

cur->random->next

上面这个位置是不是就是我们新节点13的random指向的位置?
在这里插入图片描述像这样next,cur一步一步的往后走,是不是就把新加上去的这些节点的random都配置好了。
这种方法的好处就是不管你之前节点的random指向哪个地方,我新节点都指向你这个地方的下一个位置

第三步

新节点的random都配置好了,但是我们返回的是一个新链表,所以现在我们要把之前新加的那些节点都取出来合成一个新的链表。取下来也不难,就是将一个指针从头开始遍历。

二.代码实现

第一步

	//在每个节点后面插一个复制的节点
    struct Node* cur = head;
    while(cur)
    {
        struct Node* next = cur->next;
        struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
        newnode->val = cur->val;
        cur->next = newnode;
        newnode->next = next;
        cur = next;
    }

接下来我会将代码分成几部分来讲:

    struct Node* cur = head;
    while(cur)
    {
        struct Node* next = cur->next;
        struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));

先把前戏做好,定义好三个指针:
在这里插入图片描述
这个代码时把新节点的值改成原来一样的值。

newnode->val = cur->val;

然后把三个节点链接起来就行。

cur->next = newnode;
newnode->next = next;

在这里插入图片描述

最后cur指向下一个节点继续往后走,这样就把所有的新节点和原来的节点放好了。

cur = next;

第二步

    //设置复制的节点的rondom
    cur = head;
    while(cur)
    {   
        struct Node* next = cur->next;
        if(cur->random == NULL)
        {
            next->random = NULL;
        }
        else
        {
            next->random = cur->random->next;
        }
        cur = next->next;
    }

我们先将cur指针恢复到原位:

cur = head;

然后在看循环里面的内容:

这是一个特殊的判断,如果原节点的random指向空,我们这个新节点的random也指向空。

struct Node* next = cur->next;
if(cur->random == NULL)
{
	next->random = NULL;
}

再看普通情况:

else
{
	next->random = cur->random->next;
}

把新节点的random指向原来节点的random的下一个节点。

最后cur指向下一个位置继续判断

cur = next->next;

在这里插入图片描述注意,这个下一个位置是原来链表那些节点的第二个位置:
在这里插入图片描述因为next每次在循环的开始就已经指向了当前cur的next,所以不用在对其进行相关的操作了。

第三步

    //将复制在上面的节点取下来尾插变成新的链表
    cur = head;
    struct Node* nhead = NULL;
    struct Node* tail = NULL;
    while(cur)
    {
        struct Node* next = cur->next;
        struct Node* curnext = next->next;
        if(nhead == NULL)
        {
            nhead = tail = next;
        }
        else
        {
            tail->next = next;
            tail = tail->next;
        }
        cur->next = curnext;
        cur = curnext;
    } 

最后我们就要进行收尾操作:尾插。

先定义两个指针nhead,tail然后再把cur指针复位重新指向链表最开始的位置:

cur = head;
struct Node* nhead = NULL;
struct Node* tail = NULL;

在这里插入图片描述

然后在定义两个指针:

struct Node* next = cur->next;
struct Node* curnext = next->next;

在这里插入图片描述

尾插同样要分两种情况,第一种情况就是tail,nhead为空时,也就是刚开始的时候。

if(nhead == NULL)
{
	nhead = tail = next;
}

这时候我们让nhead,tail都指向此时next指向的节点:
在这里插入图片描述这里7这个节点原来指向啥还是啥,我们现在看的像是把这个节点拿了下来。

拿下来一个节点之后,我们最后把原来两个节点还原:

cur->next = curnext;

在这里插入图片描述

然后cur继续往后跳两步:

cur = curnext;

在这里插入图片描述curnext和next每次在循环之前就已经指向了该指向的位置。

接下来我们再来看当nhead,tail不是空的情况:
在这里插入图片描述现在我们需要将next指向的节点取下来:

else
{
	tail->next = next;
	tail = tail->next;
}

在这里插入图片描述这样就把13这个节点取下来了,接下来的操作就是像这样一直循环一直循环,直到cur指针直到空时结束。现在就把最开始建立的那些新节点全部拿下来并且链接在一起了。
现在不用担心random的问题,因为第三步,根本没改变过每个节点里random的内容,所以之前指向哪里,现在还指向哪里。

最后结果:
在这里插入图片描述每个节点random指向的节点我就不画了。现在我们返回nhead就行了。

三.代码

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) {
	//在每个节点后面插一个复制的节点
    struct Node* cur = head;
    while(cur)
    {
        struct Node* next = cur->next;
        struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
        newnode->val = cur->val;
        cur->next = newnode;
        newnode->next = next;
        cur = next;
    }

    //设置复制的节点的rondom
    cur = head;
    while(cur)
    {   
        struct Node* next = cur->next;
        if(cur->random == NULL)
        {
            next->random = NULL;
        }
        else
        {
            next->random = cur->random->next;
        }
        cur = next->next;
    }

    //将复制在上面的节点取下来尾插变成新的链表
    cur = head;
    struct Node* nhead = NULL;
    struct Node* tail = NULL;
    while(cur)
    {
        struct Node* next = cur->next;
        struct Node* curnext = next->next;
        if(nhead == NULL)
        {
            nhead = tail = next;
        }
        else
        {
            tail->next = next;
            tail = tail->next;
        }
        cur->next = curnext;
        cur = curnext;
    }    
    return nhead;
}

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

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

相关文章

NetSim网络仿真使用及静态路由配置

🍰 个人主页:__Aurora__ 🍞如果文章有什么需要改进的地方还请各位大佬指正。 🍉如果我的文章对你有帮助➡️ 关注🙏🏻 点赞👍 收藏⭐️ NetSim网络仿真使用及静态路由配置。 实验要求及其步骤 使用Boson N…

Java面试笔记:Java线程安全的集合类有哪些?线程不安全的集合类有哪些?ArrayList为什么会发生并发修改异常?

一、Java的集合类有哪些? 二、如何定义集合是线程不安全的? 当多个并发同时对线程不安全的集合进行增删改的时候会破坏这些集合的数据完整性,例如:当多个线程访问同一个集合或Map时,如果有超过一个线程修改了A…

3A企业认定有哪些好处?

企业参与申报和认证有什么益处?这个问题可能应该是广大企业参与前最为关心的问题之一了 1、可快速有效提升企业资质、获得国家政府的认可;并将获得由商务部颁发的具有统一编号的牌匾和证书。 2、是企业履约能力、投标信誉、综合实力与竞争力的体现&…

数学建模--优化类模型

目录 一、根据目标函数约束条件类型分类 1、线性规划 ①线性规划模型的一般形式 ​②用MATLAB优化工具箱解线性规划 ③模型分析 2、非线性规划 ①非线性规划的基本概念 ②非线性规划的基本解法 ③二次规划 ④一般非线性规划 二、控制变量类型分类 1、整数规划 …

总结线程安全问题的原因和解决方案

一. 线程安全问题 概念 首先, 线程安全的意思就是在多线程各种随机调度的情况下, 代码不出现 bug 的情况. 如果在多线程调度的情况下, 出现 bug, 那么就是线程不安全. 二. 观察线程不安全的情况 下面我们用多线程来累加一个数, 观察线程不安全的情况: 用两个线程, 每个线程…

树--堆和优先权队列

数据结构中的堆和栈与操作系统内存划分中的堆和栈没有关系 一、堆的定义 一个大小为n的堆是一棵包含n个结点的完全二叉树,其根节点称为堆顶。 根据堆中亲子结点的大小关系,分为大堆和小堆: (1)最小堆:树中…

高斯原型网络原论文高质量翻译

论文地址:Gaussian Prototypical Networks for Few-Shot Learning on Omniglot 文章目录摘要1 引言1.1 Few-shot learning1.2 高斯原型网络2 相关工作3 方法3.1 编码器3.2 偶发性训练3.3 定义一个类3.4 评估模型4 数据集5 实验5.1 协方差估计的用法6 结论摘要 我们…

万字长文解读计算机视觉中的注意力机制(附论文和代码链接)

文中论文和代码已经整理,如果需要,点击下方公众号关注,领取,持续传达瓜货 所向披靡的张大刀 注意力机制是机器学习中嵌入的一个网络结构,主要用来学习输入数据对输出数据贡献;注意力机制在NLP和CV中均有使…

目标检测算法——YOLOv5/YOLOv7改进之结合无参注意力SimAM

目录 (一)前言介绍 1.摘要 2.不同注意力步骤比较 (二)相关实验 (三)YOLOv5结合无参注意力SimAM 1.配置.yaml文件 2.配置common.py 3.修改yolo.py SimAM:无参数Attention助力分类/检测/分…

点云应用——三维空间边界点排序+机器人轨迹引导(1)

三维空间边界点排序机器人轨迹引导一、前言二、思路一:利用重建思路三、思路二:利用PCL边界提取方法三维空间点排序四、后续一、前言 最近做了点云边界提取、并实时发送至机器人进行引导的研究,主要遇到了两个问题: 1)…

Python画爱心——一颗会跳动的爱心~

节日就快到来了,给你的Ta一个惊喜吧~ 今天给大家分享一个浪漫小技巧,利用Python制作一个立体会动的心动小爱心 成千上百个爱心汇成一个大爱心,从里到外形成一个立体状,给人视觉上的冲击感!浪漫极了↓ 微信扫码添加&a…

CUDA 从入门到放弃(一)

CUDA从入门到放弃系列包含内容 异构并行计算CUDA编程模型CUDA执行模型CUDA内存CUDA流和并发CUDA指令级原语GPU加速库多GPU编程 本文你将了解到 异构并行计算CUDA编程模型 温馨提示: 本文可能引发C/C零基础的读者不适,请谨慎观看. 一、聊聊异构并行计算 异构并行计算的本质是…

MQTT Broker mosquito配置以及使用tls证书登录附上Python调用代码

MQTT Broker mosquito配置以及使用tls证书登录 文章目录MQTT Broker mosquito配置以及使用tls证书登录1. 前言2. 安装3. mosquito相关命令3.1 运行停止查看状态3.2 创建可以登录mosquito的用户3.3 配置权限规则文件3.4 配置mosquito3.5 使用mosquito_pub和mosquito_sub测试3.5.…

web手势库Alloyfinger

前言 在上一篇文章 前端pdf预览、pdfjs的使用,我们使用pdf.js 来实现了pdf的预览。但是客户车间里的电脑是触摸屏,要求能够手势放大图纸,能够拖动图纸。最终决定使用 Alloyfinger 来解决手势的问题。 官方github https://github.com/Alloy…

计算机网络(一):计算机网络概念、功能、组成

计算机网络的概念 计算机网络:是一个将分散的、具有独立功能的计算机系统,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统 计算机网络是互连的、自治的计算机集合。 互连:互联互通 自治:无…

前端面经 前端优化

前端面经 前端优化 文章目录前端面经 前端优化HTTP/2 Web优化最佳实践DNS与解析如何使用CDN分发缓存策略页面渲染优化避免CSS、JS阻塞CSS阻塞JS的阻塞改变JS阻塞的方式使用字体图标iconfont代替图片图标降低CSS选择器的复杂性减少重绘和回流如何避免图片资源优化Webpack优化降低…

【Vue】VueCLI 的使用和单文件组件(1)

学习内容: 1)了解一下 Vue 的脚手架工具; 2) 认识一下 Vue 里面的单文件组件。‍‍ 在真正开发大型项目的时候,实际上我们并不能通过一个这样的index点html的方式去编写一个比较大型的项目,‍‍ 所以我们要学习使用 V…

JavaScript 69 JavaScript Web API 69.3 Web History API

JavaScript 文章目录JavaScript69 JavaScript Web API69.3 Web History API69.3.1 History back() 方法69.3.2 History go() 方法69.3.3 History 对象属性69.3.4 History 对象方法69 JavaScript Web API 69.3 Web History API Web History API 提供了访问 windows.history 对…

Linux进程与操作系统详解

文章目录一:冯诺依曼体系二:操作系统三:进程和PCB四:进程相关的指令五:getpid和getppid系统调用六:fork系统调用七:进程状态八:Linux下进程状态大全8.1:R(running)8.2&am…

Hive3 - HiveSQL 特征及操作

一、HiveSQL特征 Hive SQL(HQL)与SQL的语法大同小异,基本上是相通的,对SQL掌握的可以非常快的上手使用Hive SQL。不过在一些细节上需要特别注意Hive自己特有的语法知识点,下面分别进行介绍。 1. 字段数据类型 Hive数…