【数据结构与算法】链表之美-复杂链表的复制与链表的插入排序

主页:HABUO🍁主页:HABUO

🍁如果再也不能见到你,祝你早安,午安,晚安🍁


1.复杂链表的复制

题目:请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

示例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]]

分析:这是一个比较复杂的题目,我们只有见的多了之后我们可能看到这样新的题目,才会有敲门砖,又时候差的就是刚开始的敲门砖,敲门砖有了,剩下的就是用我们之前拥有的思想去实现就完了。因此呢,在这里我直接给出这个思路,以后再遇到这样类型的我们是不是就会了啊。首先,我们直接遍历是不是没办法搞啊,因为你random不知道指向谁,有些人可能会说,那我直接访问该节点的random不就行了,是的,但是如果我们链表当中,有两个相同值的节点怎么办?因为我们复制节点是复制它们的值和指向,地址是不是同等的复制下来,假如两个3,你只知道random指向3的那个节点,但是具体哪个节点我们是不是无能为力啊。因此这种直接的方法难以实现。好了,接下来很重要,1.我们为每一个节点备份一个节点,而且呢,让这个节点的next指向这个备份节点,让备份节点的next指向原链表该节点的next。2.让每一个备份节点的random指向它应该指向的备份节点,有人会问,那这咋指向,好关键点来了,你发现没有,备份节点的random是不是就是原节点的random的next啊,对不对,这就是这个题的关键。3.恢复原链表,让新链表链接起来,并返回头指针。这就是我们整体的思路。下面进行一步一步实现。

第一步:为每个节点进行备份,并且让这个节点的next指向这个备份节点,让备份节点的next指向原链表该节点的next,由于random画上之后错综复杂,不再指出,本题以示例1为导向。如下图所示:

代码实现如下:

//1.为每个链表节点备份一个节点
    Node* cur = head;
    while(cur)
    {
        Node* copyNode = (Node*)malloc(sizeof(Node));
        copyNode->val = cur->val;
        copyNode->next = cur->next;
        cur->next = copyNode;
        cur = copyNode->next;
    }

第二步 让每一个备份节点的random指向它应该指向的备份节点,我们以13节点为例,看下图就会明白。因为每一个节点的备份节点是不是就是原节点的next因此我们想要备份节点指向它所指向的random,找到原节点的random是不是就行了啊。

代码实现如下:

//2.为备份节点的random进行链接
    cur = head;
    while(cur)
    {
        //cur->random有可能指向NULL
        if(cur->random == NULL)
        {
            cur->next->random = NULL;
            cur = cur->next->next;
            continue;
        }
        //每个备份节点的random,都是原节点的random的备份节点
        cur->next->random = cur->random->next;
        cur = cur->next->next;
    }

第三步,我们破坏了原链表的链接是不是需要恢复,而且新链表也还没有连接上,下面是不是就是恢复和链接,这里就只需要多设置几个指针来回的走就ok,前面的几道题的铺垫,相信这对于我们来说应该相对很简单。

//恢复原链表,把备份链表进行链接
    cur = head;
    Node* newHead = cur->next;
    Node* copyCur = newHead;
    Node* curNext = newHead->next;
    while(cur)
    {
        cur->next = curNext;
        if(curNext == NULL)
        {
            copyCur->next = NULL;
            break;
        }
        copyCur->next = curNext->next;
        copyCur = copyCur->next;
        cur = curNext;
        curNext = curNext->next->next;
    }
    return newHead;

要注意curNext是不是到最后就为NULL了,但是我们下面还有要访问它的next的代码,因此需要在这之前做一个判断语句做一个判断,防止错误。需要注意我们这种方法是不是对原链表进行修改了,这种操作是不太好的,等到好面我们学习的深入会用更优的方法去解决。

2.对链表进行插入排序

题目:给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。

插入排序 算法的步骤:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

示例1:

输入: head = [4,2,1,3]                 输出: [1,2,3,4]

示例2:

输入: head = [-1,5,3,4,0]              输出: [-1,0,3,4,5]

分析:我们可能直接的想法就是从第一个数据起,拿到一个数据就从头遍历放到合适的位置直至最后一个节点。 但是这是链表啊,这样操作是不是代价也太高了,要是数组你发到一个合适的位置,只需要将后面的数据往后移动即可,链表不太行。所以,我们的思路是,将第一个节点当作一个新链表的起始节点,之后从后面链表当中每次取一个节点,往新链表当中进行逐一比较进行插入,当然有可能头插,也有可能尾插,也可能中间插入,所以分三种情况,这就是我们的大致思想,具体如下图所示:

所以分三种情况进行插入,头插实现如下:注意我们一开始让head指向了head->next,因为我们让第一个节点当作新链表的头了

//头插
        if(cur->val >= head->val)
        {
            head->next = cur;
            cur = head;
            newHead = cur;
            head =headNext;
            if(headNext == NULL)
                break;
            headNext = headNext->next;
            continue;
        }

中间插入实现代码如下:

while(cur)
        {
            //中间插入
            if(cur->val < head->val)
            {
                curPrev = cur;
                cur = cur->next;
            }
            else
            {
                head->next = cur;
                curPrev->next = head;
                head = headNext;
                if(headNext == NULL)
                    break;
                headNext = headNext->next;
                break;
            }
        }

尾插的话是不是就是中间插入情况的cur指向了NULL还没找到合适的位置,因此实现代码如下:

//尾插
        if(cur == NULL)
        {
            curPrev->next = head;
            head->next = NULL;
            head = headNext;
            if(headNext == NULL)
                break;
            headNext = headNext->next;
        }

所以将这些代码串起来放到一个循环当中是不是就实现了,因此完整代码如下:

 typedef struct ListNode Node;
struct ListNode* insertionSortList(struct ListNode* head) {
    if(head == NULL || head->next == NULL)
        return head;
    Node* newHead = head;
    head = head->next;
    newHead->next = NULL;
    Node* headNext = head->next;
    while(head) 
    {
        Node* cur = newHead;
        Node* curPrev = NULL;
        //头插
        if(cur->val >= head->val)
        {
            head->next = cur;
            cur = head;
            newHead = cur;
            head =headNext;
            if(headNext == NULL)
                break;
            headNext = headNext->next;
            continue;
        }
        while(cur)
        {
            //中间插入
            if(cur->val < head->val)
            {
                curPrev = cur;
                cur = cur->next;
            }
            else
            {
                head->next = cur;
                curPrev->next = head;
                head = headNext;
                if(headNext == NULL)
                    break;
                headNext = headNext->next;
                break;
            }
        }
        //尾插
        if(cur == NULL)
        {
            curPrev->next = head;
            head->next = NULL;
            head = headNext;
            if(headNext == NULL)
                break;
            headNext = headNext->next;
        }
    }
    return newHead;
}

 总结:本篇博客介绍了两个有关链表的两个题,相对于前面我们所介绍的题,可能有些难度,但这些难度是不是都是在思路上,如果有了这个思路实现起来是不是还是用我们前面的思想啊,因此我们别畏惧它,相信通过夜以继日的敲代码,我们肯定会拿到一个难题就会有思路的。大家加油!💯


🌻数据结构与算法专栏🌻

🤜别放弃是我们的底色,加油!🤛

🏋不是每一粒种子都能开花,但播下种子就比荒芜的旷野强百倍🏋

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

统计字符串中单词出现的次数

效果&#xff1a; 代码&#xff1a; #include <iostream> #include <map> #include <string> int main() {std::string s;//std::cin >> s;s " aaa aaaaa a aa aaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaa Hi I am a person a…

comfyui使用记录-PuLID_Flux模型使用

文章目录 1.PuLID模型简介&#xff1a;2.PuLID_Flux 工作流的部署流程安装pulid节点 3.部署遇到的一些问题加载这个节点错误&#xff1a;PulidFluxInsightFaceLoaderPulidFluxEvaClipLoader加载错误 4.PuLID模型的出图效果5.一些参数的设置用到的提示词 1.PuLID模型简介&#x…

threeJs学习 贴图 :地球

效果图&#xff1a; 贴图以后的效果&#xff1a; vue代码&#xff1a; <template><div class"scene_box"><p>创建纹理贴图TextureLoader</p><div class"canvas"></div></div> </template><script s…

联想品牌的电脑 Bios 快捷键是什么?如何进入 Bios 设置?

在某些情况下&#xff0c;您可能需要通过U盘来安装操作系统或进行系统修复。对于联想电脑用户来说&#xff0c;了解如何设置U盘作为启动设备是非常有用的技能之一。本文简鹿办公将指导您如何使用联想电脑的 U 盘启动快捷键来实现这一目标。 联想笔记本 对于大多数联想笔记本电…

SmartSQL:一款方便、快捷的数据库文档查询、导出工具

&#x1f6a9; 项目介绍 SmartSQL 是一款方便、快捷的数据库文档查询、导出工具&#xff01;从最初仅支持SqlServer数据库、CHM文档格式开始&#xff0c;通过不断地探索开发、集思广益和不断改进&#xff0c;又陆续支持Word、Excel、PDF、Html、Xml、Json、MarkDown等文档格式…

Transformer?Attention?——Are All You Need!

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要较为深入地讲述 transformer 模型及 attention 机制等相关深度学习的知识&#xff0c;主要介绍模型结构、原理等。Transformer 属于是当下比较流行和创新的深度学习的基础模型架构&#xff0c;主要应用于自然语言处理&a…

24.11.28 Cookie

cookie_webstorage 1.cookie 每次请求时 可以把cookie自定义的数据 传给服务端 (请求参数 请求头之外 报文传自定义数据的位置 cookie可以长期保存) cookie特点 1.数据格式只有字符串 2.按键值对存储 3.对中文支持较差(尽量不要用中文) 4.按照网站(域 domain)存储 5.可…

尚硅谷前端 (wsy答辩)

尚硅谷前端 &#xff08;wsy答辩&#xff09; 文章目录 尚硅谷前端 &#xff08;wsy答辩&#xff09;一、前端开发过程和框架1.框架目录结构认识1.程序的入口 有两个 第一个是index,html , 第二个在SRC目录下的main,js2.前端页面环境使用框架&#xff08;模板&#xff09;3、框…

不间断电源 (UPS) 对现代技术可靠性的影响

在这个技术型世界里&#xff0c;无论是在个人还是商业环境中&#xff0c;电力供应商提供的稳定供电都变得越来越重要。 不间断电源 (UPS) 系统是一种不可或缺的解决方案&#xff0c;可保证终端设备不受干扰地运行&#xff0c;在出现电源问题或故障时让用户继续工作。 这篇文章…

【05】Selenium+Python 两种文件上传方式(AutoIt)

上传文件的两种方式 一、input标签上传文件 可以用send_keys方法直接上传文件 示例代码 input标签上传文件import time from selenium import webdriver from chromedriver_py import binary_path # this will get you the path variable from selenium.webdriver.common.by i…

leetcode 二叉树的最大深度

104. 二叉树的最大深度 已解答 简单 相关标签 相关企业 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3…

MATLAB - ROS2 ros2genmsg 生成自定义消息(msg/srv...)

系列文章目录 前言 语法 ros2genmsg(folderpath)ros2genmsg(folderpath,NameValue) 一、说明 ros2genmsg(folderpath) 通过读取指定文件夹路径下的 ROS 2 自定义信息和服务定义来生成 ROS 2 自定义信息。函数文件夹必须包含一个或多个 ROS 2 软件包。这些软件包包含 .msg 文件…

使用 Elastic 和 Apple 的 OpenELM 模型构建 RAG 系统

作者&#xff1a;来自 Elastic Gustavo Llermaly 如何部署和测试新的 Apple 模型并使用 Elastic 构建 RAG 系统。 在本文中&#xff0c;我们将学习部署和测试新的 Apple 模型&#xff0c;并构建一个 RAG 系统来模拟 Apple Intelligence&#xff0c;使用 Elastic 作为向量数据库…

springboot336社区物资交易互助平台pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 社区物资交易互助平台设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff…

python爬虫案例——猫眼电影数据抓取之字体解密,多套字体文件解密方法(20)

文章目录 1、任务目标2、网站分析3、代码编写1、任务目标 目标网站:猫眼电影(https://www.maoyan.com/films?showType=2) 要求:抓取该网站下,所有即将上映电影的预约人数,保证能够获取到实时更新的内容;如下: 2、网站分析 进入目标网站,打开开发者模式,经过分析,我…

Flutter 指纹识别

在这篇博客中&#xff0c;我们将介绍如何使用 Flutter 的 local_auth 插件在 Android 和 iOS 设备上实现指纹识别功能。通过这一步一步的实现&#xff0c;我们将学习如何检查设备是否支持生物识别、如何触发指纹验证&#xff0c;并处理可能出现的错误。 效果图&#xff08;因为…

不建模,无代码,如何快速搭建VR虚拟展厅?

不建模、无代码搭建虚拟展厅&#xff0c;可以借助一些专业的虚拟展厅搭建平台或工具来实现。以下是一些具体的步骤和建议&#xff1a; 一、选择平台或工具 首先&#xff0c;需要选择一个适合的平台或工具来搭建虚拟展厅。这些平台通常提供预设的展厅模板、拖拽式编辑工具和丰富…

网络空间安全之一个WH的超前沿全栈技术深入学习之路(13-3)白帽必经之路——如何用Metasploit 渗透到她的心才不会让我释怀

欢迎各位彦祖与热巴畅游本人专栏与博客 你的三连是我最大的动力 以下图片仅代表专栏特色 [点击箭头指向的专栏名即可闪现] 专栏跑道一 ➡️网络空间安全——全栈前沿技术持续深入学习 专栏跑道二 ➡️ 24 Network Security -LJS ​ ​ ​ 专栏跑道三 ➡️ MYSQL REDIS Advan…

深入理解计算机系统,源码到可执行文件翻译过程:预处理、编译,汇编和链接

1.前言 从一个高级语言到可执行程序&#xff0c;要经过预处理、编译&#xff0c;汇编和链接四个过程。大家可以思考下&#xff0c;为什么要有这样的过程&#xff1f; 我们学习计算机之处&#xff0c;就应该了解到&#xff0c;计算机能够识别的只有二进制语言&#xff08;这是…

linux系统清理全部python环境并重装

提问 centos系统清理全部python环境并重装&#xff0c;并且使用宝塔。 解答 要在CentOS系统中彻底清理Python3环境&#xff0c;可以遵循以下步骤&#xff1a; 卸载Python3 使用rpm命令卸载所有与Python3相关的包。这个命令会查询所有已安装的与python3相关的rpm包&#xf…