单链表习题(3)(超详细)

news2024/9/24 11:27:53

前言:

  这篇文章将会是小编最近做过的习题总结的最后一篇,这一篇有些习题颇有一些难度,不过小编将会带领读者朋友们一起克服难关,下面废话不多说,开启今天的习题之旅!

目录:

1.链表分割

2.相交链表

3.随机链表的复制(本文最具有难度系数的一道题) 

正文:

1.链表分割

  老规矩,小编先给上链接:链表分割_牛客题霸_牛客网 (nowcoder.com) 

   这个题目给的描述也算是比较直白的,小编概括一下:就是给定一个链表,并且给定一个数,如果链表中的数据小于给定的这个数,那么就把这个链表放在前面,如果结点的数据大于给定的数,那么这个结点就往后放,小编在第一次看到这个题目的时候,脑子里是一点思路也没有,如果这是个数组那么这个题目可以相当于送分题,可以新设置一个数组来存放数据,把比较好的数据直接放到新数组里面就好了,我们以此类推,那么我们可不可以也新设置一个链表来进行同样的操作呢?答案是显然可以的,不过此时我们需要设置两个链表分别存数据,一个存比给定值小的,一个存比给定值大的,我们在分别存放完以后,可以把第一个链表的尾结点直接连接到第二个链表的头结点,此时我们就可以实现对于链表进行分割,下面小编给出更详细的解释:

  首先我们需要新建立两个链表,第一个链表我们暂且叫做newphead,是用来存放比给定值小的结点,第二个链表我们叫做newpphead,当然两个链表也分别有着newplist,newpplist来代替它们进行链表向后移动,此时我们用原链表进行循环,循环条件就是该链表的结点不为空,此时我们通过比较的方式来判断该结点是要放入哪个链表,在进行循环完以后,我们直接让newplist的next结点直接指向newpplist,此时原链表的数据也没有改动,我们也完成了链表的分割,此时直接返回newphead就完成了这个题目,不过我们这个代码的开头先要判断一下给定我们的链表是不是空的,如果是空的,直接返回NULL就好,不然我们可能造成对于空结点的引用,下面小编给出该题目的图文解释来帮助各位理解:

  我们需要先设置好两个链表:

  此时我们开始进行循环比较,在这里我们给定x是5,所以2比5小放入第一个链表中 :

 

  继续往后走,6比5要大,所以放入到第二个链表中:

 

  之后我们继续往后走,4要比5小,所以放入第一个链表:

  再往后循环的话原来的链表直接循环倒空了,所以此时停止循环我们把两个链表接起来:

  此时我们已经完成了链表的分割,下面小编给出代码和运行图:

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        if (pHead == NULL)
        {
            return NULL;
        }
        ListNode * newphead,* newplist,*newpphead,*newpplist,*pour = pHead;
         newplist = newphead = (ListNode*)malloc(sizeof(ListNode));
        newpplist =  newpphead = (ListNode*)malloc(sizeof(ListNode));
        while(pour)
        {
            if(pour -> val < x)
            {
                newplist -> next = pour;
                newplist = newplist -> next;
            }
            else {
            newpplist -> next = pour;
            newpplist = newpplist -> next;
            }
            pour = pour -> next;
        }
        newpplist -> next = NULL;
        newplist -> next = newpphead -> next;   //要首尾相连,我这里弄错了
        ListNode * p = newphead -> next;
        free(newphead);
        free(newpphead);
        newphead = newpphead = NULL;
        return p;

    }
};

   这个题目其实难度不算太大仔细看起来,只要我们想到可以新建一个链表来进行分割操作,那么剩下的操作就是非常容易,写起来那是行云流水,各位读者朋友一定要好好的了解这个题目是怎么做的,下面紧跟小编的步伐,开始下个题目之旅~~

2.相交链表

  老规矩,小编先给大家题目链接:160. 相交链表 - 力扣(LeetCode)

  这个题目乍一看是有一点难度,其实难度并没有很大,这个题目是让我们寻找中间节点,从例题中我们知道我们想要找到中间节点,就要让两个链表长度一样,这样让它们同时进行向下查找,就可能会找到中间节点,小编当时也是这么想着做的,只不过当时想的没有那么到位,下面小编将要带领各位读者朋友们去解决这个问题。

  首先正如小编之前说的,我们需要让两个链表的长度保持一致,所以小编的建议就是先找到最长的链表,先让这个最长的链表向后走,走的长度就是长的链表减去短的链表的长度,所以为了这么做,我们需要先判断链表的长短,小编的做法就是直接先让第一个链表是长的,第二个链表是短的,我们在使用循环来分别计算两个链表的长度以后,我们在判断一下哪一个到底是长链表,如果第一个长,那么就保持不变,反之直接让长链表是第二个,短是第一个就好了,此时我们先让长链表往后走,走完两个链表之差以后,我们在使用一个循环,让两个链表一起往后走,如果两个链表的元素相同的话,那么就遇到了相交结点,我们直接返回就好,如果循环结束还没找到,直接返回空就好了在循环结束以后,此时这个题目算是解答完了,小编还是通过图文让各位读者朋友有着更好的理解(以例题为例)。

  首先我们先确认长短链表,这里小编就不展示了,下面直接看最后结果:

  之后我们先让long1先走6 - 5 == 1步:

   此时二者处于同一起跑线,让这俩同时往后走来找相交结点,这里往后走一步:

  此时没有找到,继续往后走:

   此时我们已经找到了相交的结点,此时我们直接返回long1或者short1就好了,此时我们这个题目已经完成了图文描述,下面小编给大家展示一下这个题目的代码以及提交图:

 typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    ListNode * p1 = headA,* p2 = headB;
    int count1 = 0,count2 = 0;
    while(p1)
    {
        count1++;
        p1 = p1 -> next;
    }
    while(p2)
    {
        count2++;
        p2 = p2 -> next;
    }
    int c = abs(count1 - count2);
    ListNode * short1 = headA, * long1 = headB;
    if(count1 > count2)
    {
        long1 = headA;
        short1 = headB;
    }
    while(c--)
    {
        long1 = long1 -> next;
    }
    while(long1)
    {
        if(long1 == short1)
        return short1;
        short1 = short1 -> next;    //long 和 short 都属于关键字,不可以作为变量名
        long1 = long1 -> next;
    }
    return NULL;
}

 

3.随机链表的复制

  先给上链接:138. 随机链表的复制 - 力扣(LeetCode) 

  这个题目是最近小编做过的难度系数最大的题目了(可能是我太菜),这个题目我当时看的时候,真的就一点思路也没有,脑子里空空如也,如果只是一个单纯单链表复制的话,那么这个题目难度还没有那么夸张,但是问题就是这个题目的链表,已经不是一个单纯的单链表了,这个链表比起一般的链表,它多了一个random,这是个随机指针,这个题目最大头的部分就是解决这个随机指针的问题,下面小编先来讲述一下,我们首先除去随机指针以外链表的复制,至于随机指针,我们在复制完一次链表以后难度系数就下降了。

  首先,我们可以先新建立一个函数,这个函数的作用是用来创立新节点的,我们在每一个结点后面都插入一个结点,这个结点完完全全除去随机指针以外全部复制上一个结点的,我们就拿第一个结点为例,我们让新建的结点的数据是第一个结点的数据,让它的下一个结点指向第二个结点,让第一个结点的下一个结点指向新建结点,此时我们就建立了一个类似第一个结点的结点,此后我们在经历一次次的循环后,最后会呈现下图的效果:

  之后我们就要处理随机指针的问题了,经过上述那一步以后其实这个随机指针就好处理很多,首先我们要先确保此时随机指针指向的并不是空,所以此时我们可以拿原链表第二个链表为例子(13)。此时我们让复制好的结点的随机指针指向原链表第二个链表的随机指针的下一个链表,此时我们便可以建立起新链表之间的联系,因为原链表的下一个链表都是新建立的复制原链表的链表,所以我们在经过循环操作以后,便可以实现随机指针的指向,下面看图:

  画的略微有点潦草,各位读者朋友见谅,我们最后的操作就是断开与原链表的联系,让复制好的结点们组成新的链表,这个操作算是最为简单的操作,小编也不多加赘述了,各位读者朋友看完代码就会明白这一步,下面直接展示代码图:

typedef struct Node Node;
Node * Slistbuycode(int x)
{
    Node * p1 = (Node * )malloc(sizeof(Node));
    p1 -> next = NULL;
    p1 -> val = x;
    p1 -> random = NULL;
    return p1;

}
void fuzhijiedian(Node * head)
{
    Node * pour = head;
    while(pour)
    {
        Node * p1 = Slistbuycode(pour -> val);
        p1 -> next = pour -> next;
        pour -> next = p1;
        pour = pour -> next -> next;
    }
}

void suijijiedian(Node * head)
{
    Node * pour = head;
    while(pour)
    {
        if(pour -> random != NULL)
        {
        pour -> next -> random = pour -> random -> next;
        }
        pour = pour -> next -> next;
    }
}
struct Node* copyRandomList(struct Node* head) {
    if(head == NULL)
    return NULL;
	//首先要先复制一遍结点
    fuzhijiedian(head);
    //这里开始定义随机结点
    suijijiedian(head);
    //断开链接,完成复制
    Node * newhead = head -> next,*newlist = head -> next;
    Node * pour = head;
    while(pour -> next -> next)
    {
        pour = pour -> next -> next;
        newlist -> next = pour -> next;;
        newlist = newlist -> next;
    }
    return newhead;
}

  小编虽然这个题目解释是最少的,但是不代表这个题目简单,别看小编说的那么容易,实际伤害代码的实现还是考虑一定的基本功的,以及这个题目实现的思想,这个题目如果想明白了,难度系数会变小,这个题目就是难在这个如何实现的思想,希望读者朋友们可以好好的去理解~ 

 

总结:

  可算结束完习题篇的讲解了,小编讲述习题还是感觉是很生疏的,所以此篇文章感觉写的不算太过完美,小编上个月本来想写十篇的,但是还是暑假偷懒了,小编决定这个月完成上个月的遗憾,要写11篇!如果文章出现错误,请在评论区指出,小编一定会及时听大家给的意见,那么我们下篇文章见啦!

 

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

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

相关文章

复习Nginx

1.关于Nginx Nginx的关键特性 1.支持高并发 2.内存资源消耗低 3.高扩展性&#xff08;模块化设计&#xff09; 4.高可用性&#xff08;master-worker&#xff09; Nginx运行架构 注意 默认情况下&#xff0c;Nginx会创建和服务器cpu核心数量相等的worker进程 worker进程之间…

自从用了这些监控工具,我连续几天没睡好觉!

大家好&#xff0c;我是程序员鱼皮&#xff0c;今天分享一些很实用的系统监控告警工具。 为什么要用监控告警&#xff1f; 说到监控告警&#xff0c;没有企业开发经验的同学非常容易忽视它&#xff0c;甚至会有同学觉得没有必要&#xff0c;大不了出了 Bug 再修就是了。 这种…

MySQL:初识数据库初识SQL创建数据库

目录 1、初识数据库 1.1 什么是数据库 1.2 什么是MySQL 2、数据库 2.1 数据库服务&数据库 2.2 C/S架构 3、 初识SQL 3.1 什么是SQL 3.2 SQL分类 4、使用SQL 4.1 查看所有数据库 4.1.2 语句解析 4.2 创建数据库 4.2.1 if not exists校验 4.2.2 手动明确字符集…

第33篇 计算数据中最长的连续1的个数<三>

Q&#xff1a;如何将计算出的结果&#xff08;最长的连续1的个数&#xff09;显示在DE2-115开发板的HEX上&#xff1f; A&#xff1a;基本原理&#xff1a;DE2-115_Computer_System中的HEX并行端口作为内存映射设备连接到DE2-115开发板的七段数码管&#xff0c;每个端口都对应…

uniapp微信小程序按钮分享定制动态传参

打印 onShareAppMessage 中的传参&#xff08;注意&#xff1a;上方我定义了一个open-type为share的按钮&#xff09; 打印之后如下&#xff1a; 给按钮绑定 data-id 可以在这里的 dataset 中取到 然后根据 from 的值来动态返回分享的参数 示例代码&#xff1a; <…

通过材质节点Panner实现球体自转

纹理坐标的移动&#xff0c;可以达到球体自转的功能&#xff0c;从而减少代码的复杂度。由于是绕着一个轴转动&#xff0c;所以在u方向移动即可。 材质&#xff1a; 材质实例 运行如下&#xff1a;

怎么把视频转换成mp4格式?分享几款视频转换软件

在数字化时代&#xff0c;视频已经成为我们日常生活和工作中的重要组成部分。然而&#xff0c;不同的设备和软件可能支持不同的视频格式&#xff0c;这常常导致兼容性问题。MP4作为一种广泛支持且高质量的视频格式&#xff0c;经常被用作解决这类问题的首选方案。那么&#xff…

医疗器械维修培训哪里好

医疗器械维修培训哪里好 医学技术的应用离不开医疗设备的支持,近几年医疗行业发展迅速&#xff0c;城镇、县级、市级医院设备也都越来越多&#xff0c;医疗机构拥有大量的医疗设备&#xff0c;需要专业的维修团队来保障设备的正常运行。医疗设备的论证、验收、使用、维护、维修…

多语言海外AEON抢单可连单加额外单源码,java版多语言抢单系统

多语言海外AEON抢单可连单加额外单源码&#xff0c;java版多语言抢单系统。此套是全新开发的java版多语言抢单系统。 后端java&#xff0c;用的若依框架&#xff0c;这套代码前后端是编译后的&#xff0c;测试可以正常使用&#xff0c;语言繁体&#xff0c;英文&#xff0c;日…

WebSocket 协议与 HTTP 协议、定时轮询技术、长轮询技术

目录 1 为什么需要 WebSocket&#xff1f;2 WebSocket2.1 采用 TCP 全双工2.2 建立 WebSocket 连接2.3 WebSocket 帧 3 WebSocket 解决的问题3.1 HTTP 存在的问题3.2 Ajax 轮询存在的问题3.3 长轮询存在的问题3.4 WebSocket 的改进 参考资料&#xff1a; 为什么有 h…

leetcode提示LeetCode extension needs Node.js installed in environment path

背景 系统&#xff1a;mac node版本 已通过nvm安装了多个版本node&#xff0c;并通过nvm alias default XX指定了node默认版本 描述&#xff1a;vscode安装了leetcode后&#xff0c;提示&#xff1a;LeetCode extension needs Node.js installed in environment path 问题…

leetcode958. 二叉树的完全性检验,层序遍历的巧用

leetcode958. 二叉树的完全性检验 给你一棵二叉树的根节点 root &#xff0c;请你判断这棵树是否是一棵 完全二叉树 。 在一棵 完全二叉树 中&#xff0c;除了最后一层外&#xff0c;所有层都被完全填满&#xff0c;并且最后一层中的所有节点都尽可能靠左。最后一层&#xff0…

Web安全学习顺序:从零到精通的指南

随着互联网的迅猛发展&#xff0c;Web安全已成为一个日益重要的领域。无论是企业还是个人&#xff0c;都需要关注并提升自身的Web安全防护能力。对于初学者而言&#xff0c;如何系统地学习Web安全知识&#xff0c;掌握相关技能&#xff0c;成为了一个亟待解决的问题。本文将为你…

C# 串口通信(通过serialPort控件发送及接收数据)

连接串口 界面设计打开串口发送数据通过文件发送发送数据 接收数据 首先可以在 工具箱中搜索serialport&#xff0c;将控件拖到你的Winfrom窗口。 界面设计 打开串口 private void Connect_Click(object sender, EventArgs e){serialPort1.PortName comboBox2.Text;//端口名s…

颜色传感器 - 从零开始认识各种传感器【二十三期】

颜色传感器|从零开始认识各种传感器 1、什么是颜色传感器 颜色传感器&#xff08;Color Sensor&#xff09;是一种能够检测和识别颜色的传感器&#xff0c;它广泛应用于工业自动化、机器人技术、智能家居、消费电子等领域。颜色传感器通过测量物体表面反射的光来确定其颜色&a…

类和对象(上) - c++

1.类的定义 1.1 类定义格式 class 是定义类的关键字 ,后跟类的名字,{}部分为类的主体,(注意:最后类定义结束时不要忘了 ; )。 类体中内容称为类的成员&#xff1a;类中的变量称为成员变量; 类中的函数称为成员函数。在c中,struct也可以定义类(c兼容c语言),同时struct升级成类…

武汉流星汇聚:跨境电商桥梁连接中国与世界,中国产品畅销全球

在全球经济一体化的大背景下&#xff0c;零售电商行业以其独特的魅力和无限潜力&#xff0c;正引领着全球商业模式的深刻变革。特别是中国卖家&#xff0c;通过跨境电商平台这一桥梁&#xff0c;轻松触达全球消费者&#xff0c;实现了商品的快速流通和市场的广泛覆盖&#xff0…

Spark 基础 与 安装

Spark 基础 一、MapReduce编程模型的局限性 1、繁杂&#xff1a;只有Map和Reduce两个操作&#xff0c;复杂的逻辑需要大量的样板代码 2、处理效率低&#xff1a; Map中间结果写磁盘&#xff0c;Reduce写HDFS&#xff0c;多个Map通过HDFS交换数据 任务调度与启动开销大 3、…

十城联动共建生态登陆山东 纷享销客从原厂型向生态型CRM进化

7月30日&#xff0c;纷享销客渠道生态伙伴发展共建会之山东专场盛大举行&#xff0c;百余家优秀伙伴到场共享CRM领域高质量增长新机遇。2024年&#xff0c;纷享销客将坚定不移地从原厂型向生态型CRM厂商进化&#xff0c;把伙伴们扶上马&#xff0c;送一程&#xff0c;共发展&am…

Java--异常

目录 异常的概念异常的体系结构异常抛出异常处理异常throws声明try-catch捕获 异常处理流程自定义异常类 异常的概念 Java中&#xff0c;程序执行过程中发生的不正常的行为称为异常。 我们之前学数组的时候可能会遇到的数组越界异常&#xff1a;ArrayIndexOutOfBoundsException…