数据结构——链表OJ题目讲解(1)

news2024/9/19 10:48:49

作者:几冬雪来

时间:2023年3月7日

内容:数据结构链表OJ题目讲解

题目来源:力扣和牛客

目录

前言:

刷题:

1.移出链表元素:

2.链表的中间结点:

3. 链表中倒数第k个结点:

结尾: 


前言:

在上一篇博客中我们对链表内容的讲解也就结束了,但是链表作为我们一个难度跨度较大的一个专题,因此单单看是不行的。在学习链表的过程中,如果要进一步提升自己,刷题是必不可少的一个环节。

刷题:

在学习数据结构的过程中,刷题能够提高我们写题的能力,帮助我们以后在在找工作的时候可以游刃有余,同时也可以检验出我们的不足之处,在写的时候还会有一些平常没有遇到的坑在等着我们,下面我就找来了力扣和牛客上找来一些有关链表的题目来讲解。 

1.移出链表元素:

 

题目要求删除链表中的某一数据,看似我们在写链表的代码中也有类似的操作,只不过它们还是有点不同。在我们书写的链表代码中,只是删除一次val而已,而这个题目则需要我们删除所有val,二者有所区别。

而在刷数据结构的题的时候,画图是我们一定要学会的一种技能。 那么这一题的运行是怎么样的呢?

因为是链表,因此一开始我们创建两个指针,prev指针指向我们第一个结点,cur指向第二个结点。 如果cur等于val的话,我们就将cur->next赋值给prev->next,然后将cur的值释放

这里我们将代码写出来,先创建两个空指针,一个置为空,一个指向第一个结点的位置,然后进行循环,循环条件是cur不为0。再下来就进行判断,如果cur的下一个结点不为val,则把cur赋予给prev,再让cur来到下一个结点

如果cur为val,则只需要将原cur的下一个结点的地址赋值给prev的next,后将cur释放。最后把prev->next赋值给cur,让它依旧指向prev的下一个结点。 

这里要注意最后应该是cur = prev->next,如果是cur = cur->next的话,我们会访问到空指针。 

代码到这里就结束了吗?我们运行出来看一看,但是这里的结果却十分出乎意料。

我们的案例并没有通过,这是为什么?这就需要分析一下了。我们从这个题目的用例中取一个用例来说明。

类似这个用例,假设第一个结点就是我们要删除的值,这个时候我们上面的代码if语句条件不满足进入else语句。然而因为if语句没有进行,我们的prev的值依旧为空,下面prev->next=cur->next就会出错。所以我们要对代码进行分开讨论。

就像上面的代码这样,如果第一个if语句条件不成立,那么就进入else语句中。这里我们在分支语句中再嵌套一个分支语句。如果我们的prev为空,那就说明第一个结点的值就是要删除的值。然后这里将我们的头结点改为cur->next,而后将cur释放,最后因为头结点的删除,因此要将head赋值给cur作为指向新的头结点的指针

结果证明我们的想法是正确的。

其实对于这道题目,我们还有其他的解决方法。这里我们可以将不是val的值尾插到新链表

像我们这张图,我们创建一个新链表newHead并在一开始将它置空。如果第一个结点不为val,则我们让cur = tail,作为我们新指针的头结点。而后cur向下移动,如果不为val则给新的链表然后tail也向下移动,如果不是则跳过这个值

依旧开始创建指针,下来函数循环。如何cur指向的不是val,则进入if语句中进行嵌套的分支语句。

而这里的嵌套的分支语句中,if语句只执行一次,当tail为空的时候,也就说明我们的新指针里面还没有值,这里就要将cur赋值给tail和newHead作为新指针的头结点。(尾插要赋值) 

再然后让tail->next指向cur也就是第二个结点,接下来tail向下走一步来到第二个结点的位置,cur向下走一步来到cur的下一个结点。 

如果找到val的值的话,我们就创建一个临时指针next,然后将cur下一个结点赋值给next,next就是cur的下一个结点,为的是保存我们这个结点。赋值完了之后我们将cur释放掉,然后将next赋值给cur。 

看似没有问题,但是实际上是会出错的,而链表中如果出问题的话,那么十有八九是野指针的存在

其实是这个代码出了问题,也不能说是问题,只能说不完整。那么为什么会不完整呢?在怎么的这个题目中最后一个数据是要删除的,然后在代码的这个地方,我们创建了一个临时变量来保存cur的下一个结点,然后将cur释放最后cur = next。但是我们tail->next依旧存在着原来没删除前值的地址,而后我们将其释放,这里就会变成一个空指针形式

而要解决这个问题也是十分简单。 

在循环结束后我们将tail->next置空即可,这样就避免了野指针的出现。 书写完了之后我们再次运行程序,但是很遗憾这里我们的代码函数存在问题。

 

从代码用例我们可以分析出,这是链表为空的情况,如果链表为空,这里我们程序的循环就不会运行。然后tail->next = NULL这个地方就出错了。

要修复这个问题其实也是十分的简单,只要在程序的开头对我们的链表是否为空进行判断即可。 

但是即使这样,我们的代码依旧有问题存在。 

当我们的代码全是7,删除的也是7的时候,这个时候代码也会出错。那个时候我们的代码会将全部结点删除掉了,没有结点尾插,newHead和tail依旧为空,还是tail->next = NULL这个地方的问题。 那么代码还是需要改进。

在这里我们用一个分支语句将它包裹住,如果结点全部删除tail为空,这个代码也不会执行程序也就不会出问题。再次运行程序看看结果。

终于在我们改了好多次之后,我们的代码终于运行成功了。下面我们就将我们的代码全部放上来。 

这道题我们到这里就结束了。下面还有一道题目需要我们解决。

2.链表的中间结点:

这道题是人我们求链表的中间结点的值,而解决这道题的方法有许多中。类似我们的最传统的方法,先计算链表的长度然后找中间值。 

又因为这道题目过于简单,因此这道题通常都有一些限制所在。例如:只能遍历一遍链表。如果是这样的话,那么上面的传统方法就不用了。 

同样的这道题也可以通过创建数组来解决,但是那种方法就类似于顺序表的写法,比起链表过于复杂。 为了比较快速的解决这道题,这里我们要了解一个解题方法——快慢指针。那么什么是快慢指针呢?

 

快慢指针的工作原理就类似我们上边这个图,一开始创立一个快指针和一个慢指针都指向头结点,而后开始移动快指针一次移动两步,慢指针则一次移动一步快指针的移动速度是慢指针的两倍,因此当指针fast走完的时候,slow刚刚好久到了链表的中间

然而这个代码还有另一个影响因素,那就是数组的个数为单数还是偶数。如果链表的结点个数是单数,则中间结点就只有一个,如果结点个数为偶数则中间结点有两个,依题得知如果中间结点个数为两个我们要取后面的那个结点

我们要将它进行分类讨论。 

先创建两个指针,两个指针都指向链表的头结点因为fast走的比slow指针要快,因此我们选用fast指针作为循环条件判断

两种判断的原理如图所示。而后就是循环,slow每次走一步,fast指针每次走两步,最后返回slow指针。运行起来看看结果。

通过测试可以看出我们的想法没有问题,也可以成功输出。

下一道题目则是来自我们的牛客网的题库。 

3. 链表中倒数第k个结点:

 

 这一题函数运用我们的快慢指针,只不过和上面的比较时间的快慢不一样,在这里我们比较的是个数。那么个数是怎么样快慢的呢?首先我们要知道一个点。

尾结点和倒数第k个结点之间的距离是k-1

那么解决这道题就有两种方法,我们画个图出来看看。

 

这就是我们的解题原理,既然倒数第k个结点和尾结点之间的距离是k-1。那么在快慢指针中我们就可以先让快指针先走k-1步,而后快指针和慢指针同时向后运行距离相差k-1,当我们的fast走到尾结点的时候,这个时候slow就是倒数第k个结点

也可以让fast先走k步,最后slow要在倒数第k个结点处的话,fast要指向空。两种方法都是可以的。而这个问题我采用了第二种方法

首先先对链表为空进行处理,接下来还是创建两个指针并都指向链表的头结点。然后先一个循环来让fast先走k步,最后再创建一个循环来让两个指针同时往后走,并在结束的时候返回slow的指针

但是这里我们的代码是不完全的,那它还存在什么问题呢? 在调试中我们可以看出如果在这里想要访问倒数第6个的结点,但是链表总共才5个数据,这样做就造成了空指针的问题。 那要怎么样修改呢?

 

改动的地方就是这里,如果fast为0了,我们直接返回空。但是我们的用例不止一个地方报错。在第二个用例处我们依旧报错了。

其实这里的问题更加容易解决。这里是因为的fast赋值比判断先执行,导致了第二个用例本来指向最后一个结点指向了最后一个结点后面的空。fast变为了空,因此我们要将这个判断语句调整到执行语句的上面

 

这个问题也就得到解决了。 

依旧我们将书写的代码放过来。

 

到这里这篇博客要刷的题就结束了。

结尾: 

通过今天刷的链表的题目,我们对链表的知识得到了进一步的提高,题目里面的有些坑也值得我们去深思,一些日常学习看起来微不足道的点,在正式写代码的时候可能就会出现致命的错误。如果想要更加提升自己链表能力的同学也可以多去找题目写。最后希望这篇博客能在写题的时候为各位提供帮助。

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

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

相关文章

第六届省赛——8移动距离(总结规律)

题目:X星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为1,2,3...当排满一行时,从下一行相邻的楼往反方向排号。比如:当小区排号宽度为6时,开始情形如下:1 2 3 4 5 612 11 10 9 8 713 14 1…

【论文简述】MVSTER: Epipolar Transformer for EfficientMulti-View Stereo(ECCV 2022)

一、论文简述 1. 第一作者:Xiaofeng Wang 2. 发表年份:2022 3. 发表期刊:ECCV 4. 关键词:MVS、3D重建、Transformer、极线几何 5. 探索动机:融合多视图代价体很关键,现有的方法效率低,引入…

【Git】P2 分支(创建分支,合并分支,分支冲突,分支分类)

分支分支的概念2077 与 分支git - 分支分支语句查看与创建分支切换与删除分支合并分支分支冲突分支分类分支的概念 什么是分支? 2077 与 分支 我最喜欢的游戏就是 赛博朋克2077,美国末日 和 GTA,下图是2077的存档。 存档非常多的原因是因为…

JavaScript 语句、注释和代码块实例集合

文章目录JavaScript 语句、注释和代码块实例集合JavaScript 语句JavaScript 代码块JavaScript 单行注释JavaScript 多行注释使用单行注释来防止执行使用多行注释来防止执行JavaScript 语句、注释和代码块实例集合 JavaScript 语句 源码 <!DOCTYPE html> <html> &…

Springboot 读取模板excel信息内容并发送邮件, 并不是你想想中的那么简单

Springboot 读取模板excel信息内容并发送邮件 背景技术选型搭建过程数据加密隐藏问题暴露背景追溯解决背景 在我们日常开发中, 会遇到这样一种场景, 就是读取表格中的数据, 并将数据以附件的形式通过邮箱发送到表格中的每个人 即: excel 读取 excel 写入 发送邮件(携带附件), 例…

Volsdf Sampling algorithm

l论文作者开发一个算法计算抽样S方程中使用 I(c,v)≈I^S(c,v)∑i1m−1τ^iLiI(\boldsymbol{c}, \boldsymbol{v}) \approx \hat{I}_{\mathcal{S}}(\boldsymbol{c}, \boldsymbol{v})\sum_{i1}^{m-1} \hat{\tau}_{i} L_{i} I(c,v)≈I^S​(c,v)i1∑m−1​τ^i​Li​ 首先是通过利用…

小区业主入户安检小程序开发

小区业主入户安检小程序开发 可针对不同行业自定义安检项目&#xff0c;线下安检&#xff0c;线上留存&#xff08;安检拍照/录像&#xff09;&#xff0c;提高安检人员安检效率 功能特性&#xff0c;为你介绍小区入户安检系统的功能特性。 小区管理;后台可添加需要安检的小区…

LeetCode-96. 不同的二叉搜索树

题目来源 96. 不同的二叉搜索树 递归 1.我们要知道二叉搜索树的性质&#xff0c;对于一个二叉搜索树&#xff0c;其 【左边的节点值 < 中间的节点值 < 右边的节点值】&#xff0c;也就是说&#xff0c;对于一个二叉搜索树&#xff0c;其中序遍历之后形成的数组应该是一…

分布式系统中的补偿机制设计问题

我们知道&#xff0c;应用系统在分布式的情况下&#xff0c;在通信时会有着一个显著的问题&#xff0c;即一个业务流程往往需要组合一组服务&#xff0c;且单单一次通信可能会经过 DNS 服务&#xff0c;网卡、交换机、路由器、负载均衡等设备&#xff0c;而这些服务于设备都不一…

C++:初识函数模板和类模板

目录 一. 泛型编程 二. 函数模板 2.1 什么是函数模板 2.2 函数模板的实例化 2.2.1 函数模板的隐式实例化 2.2.1 函数模板的显示实例化 2.3 函数模板实例化的原理 2.4 模板函数调用实例化原则 三. 类模板 3.1 什么是类模板 3.2 类模板的实例化 一. 泛型编程 泛型编程…

Qt广告机客户端(下位机)

目录功能结构adClient.promain.cppadclient.h 客户端adclient.cpp 客户端addate.h 时间处理addate.cpp 时间处理adsocket.h 客户端Socket处理adsocket.cpp 客户端Socket处理weather.h 天气信息处理weather.cpp 天气信息处理rollmassege.h 滚动信息处理rollmassege.cpp 滚动信息…

DCC数字管护生命周期模型解读

实话说&#xff0c;对于Digital Curation笔者真心不知道应该怎么翻译。本文借用了钱毅老师的观点&#xff0c;姑且翻译成“数字管护”&#xff0c;详见《从保护到管护&#xff1a;对象变迁视角下的档案保管思想演变》&#xff08;《档案学通讯》&#xff0c;2022年第2期&#x…

数据库基本功之SQL的数据类型

1.四种基本的常用数据类型 1.1 字符型 char # 固定字符,最长2000个 varchar2 # 可变长字符,最长4000个,最小值是1 nchar/nvarchar2 # 类型的列使用国家字符集 raw & long raw # 固定/可变长度的二进制数据长度 最2G,可存放多媒体图象声音等.(老类型,逐步淘汰) LONG …

浅谈CSRF跨域读取型漏洞之JSONP劫持

目录 前提知识 CSRF JSONP jsonp漏洞 原理 过程 复现 漏洞挖掘思路 漏洞防御 前提知识 CSRF 提起CSRF&#xff0c;可能很多人都会想到修改个人资料、授权登陆等攻击场景&#xff0c;可以发现这两个场景都是写入型的CSRF漏洞&#xff0c;通常会忽视更常见的读取型的CS…

MP与IP-Trunk技术讲解

目录 PPP MP技术 将PPP链路直接绑定到VT上实现MP 按照PPP链路用户名查找VT实现MP IP-Trunk技术 PPP MP技术 MP&#xff08;MultiLink PPP&#xff09;将多个PPP链路捆绑使用的技术&#xff08;Serial接口、POS接口等&#xff09; 实现方式 可以采用虚拟VT接口实现MP PPP链路…

通过canvas画出爱心图案,表达你的爱意!

通过canvas画出爱心图案&#xff0c;浏览器可以使用以下js代码&#xff0c;新建对象时&#xff0c;会自动呈现动画效果&#xff0c;代码文末可下载。 点击免费下载源码 let HeartCanvas new HeartCanvas() /*** 爱心* Heart Canvas*/class HeartCanvas {/*** param hMin 颜…

怎么恢复本地磁盘里的数据?电脑本地磁盘数据恢复7种方案

演示机型&#xff1a;技嘉 H310M HD22.0系统版本&#xff1a;Windows 10 专业版软件版本&#xff1a;云骑士数据恢复软件3.21.0.17本地磁盘是什么意思&#xff1f;所谓的本地磁盘是指安装在电脑主板上&#xff0c;不能随便拔插的硬盘&#xff0c;通俗易懂的讲就是电脑内部安装的…

Spring Cloud融合gateway构建的API网关服务 | Spring Cloud 12

一、Spring Cloud Gateway 1.1 概述 所谓的网关就是指系统的统一入口&#xff0c;它封装了运用程序的内部结构&#xff0c;为客户端提供统一的服务&#xff0c;一些与业务功能无关的公共逻辑可以在这里实现&#xff0c;诸如认证、鉴权、监控、路由转发等。 Spring Cloud Gat…

北斗导航 | PPP-RTK:CLASLIB 0.7.2 版本中文手册(CLASLIB ver. 0.7.2 Manual)

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== CLASLIB ver. 0.7.2 Manual

Hevc变换系数扫描

量化后变换系数的熵编码在整个熵编码中占有举足轻重的地位&#xff0c;由于量化后变换系数大多为零值或者幅度较小的值&#xff0c;如何有效利用这一特性是熵编码的关键环节&#xff0c;H265/HEVC标准中&#xff0c;亮度数据和色度数据均以变换块TB为单位&#xff0c;通过编码非…