力扣 单链表元素删除解析及高频面试题

目录

删除元素的万能方法

构造虚拟头结点来应对删除链表头结点的情况

一、203.移除链表元素

题目

题解

二、19.删除链表中倒数第K个节点

题目

题解

三、

83.删除某个升序链表中的重复元素,使重复的元素都只出现一次 

题目

题解

82.删除某个升序链表中的重复元素且不保留,即只含原始链表中没有重复出现过的元素

题目

题解


删除元素的万能方法

删除元素的万能方法,就是找到目标节点,保存目标节点的前驱节点的引用,让前驱结点的next,指向目标节点的后继节点。这样,没有目标节点的引用,它将被gc回收。

  • 这里cur是前驱节点的引用,cur.next指向目标节点。删除元素步骤如下:首先我们在题目中通过各种判断,确定cur.next指向的,就是我们需要删除的目标节点 。然后,把cur.next.next赋值给cur.next。这也就是说,让cur.next也指向后继结点。
  • 此时前驱结点的next已经指向了后继结点。那原来的目标节点呢?已经不连接在链表中了,并因其没有引用变量指向,将会被gc回收。

但这个时候有些细心的小伙伴可能会有疑问:你这删除是讲清楚了,但是我发现这样的删除需要有前驱节点和后继节点,那如果是删除链表头结点(没有前驱结点)或是删除链表尾结点(没有后继结点),那怎么办呢?哈哈,先告诉结论:链表尾结点的状况,上述做法可以包含进来。而链表头结点,要么分情况讨论,要么使用我们接下来使用的方法:建立虚拟链表头结点。

构造虚拟头结点来应对删除链表头结点的情况

在上文中我们得出尾结点是包含在cur.next = cur.next.next中的。但是对于头结点就不好使了。为什么呢?因为如果后继结点是null,那还可以把null赋给一个引用,但是如果前驱结点cur为null,那么cur.next就会直接抛出一个异常了!那我们怎么办呢?第一种方法是if-else判断,如果删除元素是头结点就直接返回head.next。但是这样写的话代码比较乱,这里介绍一种更好的办法:构造虚拟头结点。这是啥意思呢?所谓虚拟头结点,就是在原链表的头结点前方接上一个节点。这样,原链表的所有结点在新链表中都不是头结点了,自然就可以沿用上面的赋值式。

如图,先创建虚拟头结点temp(值设为-1),然后让它的next指向原链表头结点,然后让cur初始化为temp(cur = temp),这样cur就永不为null,删除节点永远有前驱节点,cur.next = cur.next.next就可以继续使用。

这样我们就成功用cur.next = cur.next.next完成了头结点的删除。

需要注意的是,此方法到最后,返回删除元素后的新链表的头结点时,应该返回的是temp.next,而不是temp。

一、203.移除链表元素

题目

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

题解

通过在头节点前增加虚拟头节点(哨兵),头结点则变为普通结点,则不需要判断头节点是否为待删除的节点,但是在返回的时候需要返回的是虚拟头节点的下一节点而不是虚拟头节点。

public class ListNode {public int val;public ListNode next;
}
public static ListNode deleteListNode(ListNode head,int val){//删除所有val结点,删除节点的方式是找到前驱节点cur,让cur.next = cur.next.nextListNode temp = new ListNode(-1);temp.next = head;ListNode cur = temp;//构造了带虚拟头结点的链表并初始化cur//用cur.next.val判断是因为cur.next.val == val判断cur.next是否为目标节点,//这样cur就是前驱结点的引用了。我们在删除节点时必须考虑到保留前驱结点引用。while (cur.next != null){if (cur.next.val == val){cur.next = cur.next.next;//删除目标节点。cur不移动,继续与下一个节点比较}else {cur = cur.next;//如果当前cur.next不符合删除要求,cur 向链表后方移动一次再次比较}}return temp.next;
}

二、19.删除链表中倒数第K个节点

题目

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

题解

这里我们使用双指针法,先让快慢指针步差为K+1,然后快慢指针同步移动,这样当快指针指向链表末尾的null时(你也可以理解成链表最后一个元素是倒数第1节点,最后一个元素的null指针域是倒数第0节点),即快指针指向倒数第0个节点时,因为步差K+1,所以这时慢指针指向倒数第K+1个节点,也就是前驱节点。不知道你发现没有,2)题这类问题的核心,就是在于寻找删除节点的前驱结点。

然后按部就班的删除即可。

public static ListNode deleteLastKByTwoPointers(ListNode head,int k){ListNode temp = new ListNode(-1);temp.next = head;ListNode slow = temp;ListNode fast = temp;//初始化,虚拟头结点构造,快慢指针指向虚拟头结点//fast先走k+1步for (int i = 0; i < k+1; i++) {fast = fast.next;}while (fast != null){fast = fast.next;slow = slow.next;}//同步前进直到fast为nullslow.next = slow.next.next;//删除待删除的节点return temp.next;
}

三、

这类问题的关键在于你的cur引用是指向第一个重复元素,还是指向第一个重复元素的前驱结点。

(1)如果cur指向第一个重复元素,那么把cur.val和cur.next.val比较,如果相等就删除cur.next,这样就删除了所有和cur.val相同值的节点,但还留下了一个cur节点。这样会留下一个重复节点,即LeetCode83。

  • cur.val==cur.next.val ?删除cur.next:cur向后移动
  • 最后重复元素留下一个节点0

(2)如果cur指向第一个重复元素的前驱节点,那么把cur.next.val和cur.next.next.val比较,如果相等就存下重复元素的值(6),然后cur.next.val逐个与存储值比较,是就删除cur.next,这样就删除了所有重复结点。这样重复值节点一个也不会留下,即LeetCode82。

  • 如果cur.next.val==repeatData,循环删除直到没有repeatData节点为止

83.删除某个升序链表中的重复元素,使重复的元素都只出现一次 

题目

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

提示:
链表中节点数目在范围 [0, 300] 内
-100 <= Node.val <= 100
题目数据保证链表已经按升序 排列

题解

由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是连续的,这个很关键。因此我们只需要对链表进行一次遍历,就可以删除重复的元素。

public static ListNode deleteRepeatAndSaveOne(ListNode head){if (head == null){return null;}
//这题不用构建虚拟头结点ListNode cur = head;while (cur.next != null){//逐个逐个比较直到后继结点为nullif (cur.val == cur.next.val){//如果值相同,则删除cur.next, cur不移动,和下一个cur.next继续比较cur.next = cur.next.next;}else {cur = cur.next;//如果值不同,则移动cur至后继结点,开始下一轮比较}}return head;
}

82.删除某个升序链表中的重复元素且不保留,即只含原始链表中没有重复出现过的元素

题目

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

提示:
链表中节点数目在范围 [0, 300] 内
-100 <= Node.val <= 100
题目数据保证链表已经按升序 排列

题解

这道题和上一道题类似83. 删除排序链表中的重复元素,但是这里要求的是删除所有重复的链表节点,而上一题可以保留一个。
分析一下这道题,删除所有重复的节点,加入有两个节点被删除,例如[1,2,2,3],那么在进行对比的时候需要保留一个节点在1的位置,寻找重复的两个指针一个左边的在第一个2,右边的第一次在第二个2,第二次在3。这个时候我们需要把1->3连接起来。

流程如下:

  1. 一边遍历、一边统计相邻节点的值是否相等,如果值相等就继续后移找到值不等的位置,然后删除值相等的这个区间。
    1. 设置一个虚拟节点,将虚拟头节点和原链表头节点连接起来
    2. 从虚拟头节点位置开始访问
    3. 只要当前访问节点的下一个节点与下下个节点都存在,就继续访问下去
    4. 在访问过程中,如果下一个节点与下下个节点相同,那么说明与这个节点值相同的所有节点都应该被删除掉。
  2. 删除的方法是先记录这个值,利用 while 循环,不断的查找出那些相同的节点值来,每次找到了一个相同的值,那么当前访问的节点 cur 就越过这个节点。
  3. 在访问过程中,下一个节点与下下个节点不相同,说明 cur 可以加入到最终的结果链表中,那么继续访问后面的节点。

 代码如下:

class Solution {public ListNode deleteDuplicates(ListNode head) {// 一开始设置一个虚拟节点,它的值为 -1,它的值可以设置为任何的数,因为我们根本不需要使用它的值ListNode dummy = new ListNode(-1);// 将虚拟头节点和原链表头节点连接起来// 添加虚拟头节点之后,原链表的每个节点的地位都是一样的dummy.next = head;// 从虚拟头节点位置开始访问ListNode cur = dummy;// 只要当前访问节点的下一个节点与下下个节点都存在,就继续访问下去while (cur.next != null && cur.next.next != null) {// 在访问过程中,会出现两种情况// 1、下一个节点与下下个节点相同,那么说明与这个节点值相同的所有节点都应该被删除掉if (cur.next.val == cur.next.next.val) {// 删除的方法是先记录这个值int value = cur.next.val;// 利用 while 循环,不断的查找出那些相同的节点值来while (cur.next != null && cur.next.val == value) {// 每次找到了一个相同的值,那么当前访问的节点 cur 就越过这个节点cur.next = cur.next.next;}// 2、下一个节点与下下个节点不相同,说明 cur 可以加入到最终的结果链表中} else {// 那么继续访问后面的节点cur = cur.next;}}// 最终返回虚拟头节点的下一个节点就行了return dummy.next;}
}

我们发现,其实单链表删除都是一样的套路。找好前驱节点,明晰删除条件,遍历小心谨慎,脑中不断构建图,其实单链表删除真的不难。

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

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

相关文章

2023年第十四届蓝桥杯JavaB组省赛真题及全部解析(下)

承接上文&#xff1a;2023年第十四届蓝桥杯JavaB组省赛真题及全部解析&#xff08;下&#xff09;。 目录 七、试题 G&#xff1a;买二赠一 八、试题 H&#xff1a;合并石子 九、试题 I&#xff1a;最大开支 十、试题 J&#xff1a;魔法阵 题目来自&#xff1a;蓝桥杯官网…

【星海随笔】vue+vite

开头问一个问题&#xff0c;我发现有的人粉丝是点赞数的好几倍&#xff0c;可能和必须关注他才能阅读他的文章有关。 所以问一下怎么设置为关注才能查看该文章。 screen -ls #查看 id 列表 screen -S <session_name> # 创建一个会话 screen -R <session_id> # 根据…

iconfont-阿里巴巴矢量图标库 在vue项目使用记录

官网地址&#xff1a;https://www.iconfont.cn/manage/index?manage_typemyprojects&projectId4539761 第一步&#xff1a; 下载资源 ->解压到项目文件夹 第二步 在项目中main.ts 或者main.js 引入资源 import //assets/iconfont/font/iconfont.js; import //assets…

IBM Spectrum LSF RTM,针对 IBM Spectrum LSF 环境的高级报告、跟踪和监控工具

亮点 为 IBM Spectrum LSF 环境提供性能监控和报告 监控 FlexNet Publisher 和 Reprisebased 许可证的使用&#xff0c;提供详细和总结性报告 通过多个级别&#xff08;包括应用程序和组织&#xff09;的报告来监控共享存储的利用率 提供强大的生产力工具&#xff0c;包括操…

JVM专题五:类加载器与双亲委派机制

通过上一篇Java的类加载机制相信大家已经搞明白了整个类加载从触发时机&#xff0c;接着我们就来看下类加载器&#xff0c;因为类加载机制是有加载器实现的。 类加载器的分类 启动类加载器 Bootstrap ClassLoader 是 Java 虚拟机&#xff08;JVM&#xff09;的一部分&#x…

斜光测距的原理及python实现

1.前言 最近做了一个基于opencv的斜光测距的小项目&#xff0c;东西不多&#xff0c;但是很有意思&#xff0c;值得拿出来学一学。项目里面需要比较精确的定位功能&#xff0c;将前人matlab代码移植到python上&#xff0c;并且做了一些优化&#xff0c;简化逻辑(毕竟我是专业的…

我教会了我妈搭建自己的 AI 聊天机器人...

在这个人工智能爆发的年代,ChatGPT、Claude、Kimi、文心一言等 AI 大模型产品火遍全网,仿佛一夜之间,人人都在谈论 AI。 作为普通人的我们,难道就只能看着程序员们尽情玩耍,自己却无法参与其中吗?NO! 鉴于最近自己社群学员和粉丝的要求&#xff0c;一进来大家无论是不是小白…

Linux防火墙【SNAT,DNAT】

NAT: 支持PREROUTING&#xff0c;INPUT&#xff0c;OUTPUT&#xff0c;POSTROUTING四个链 请求报文&#xff1a;修改源/目标IP&#xff0c; 响应报文&#xff1a;修改源/目标IP&#xff0c;根据跟踪机制自动实现 NAT的实现分为下面类型&#xff1a; SNAT&#xff1a;source…

如何实现数字人系统私有化部署?数字人源码部署教程简易版来了!

当前&#xff0c;数字人行业的市场前景和应用潜力不断显现&#xff0c;不少创业者都想要通过学习数字人源码部署教程来搭建属于自己的数字人系统&#xff0c;以此获得进军数字人行业的入场券。而事实上&#xff0c;该想法本身当然是固然值得鼓励的&#xff0c;但就目前的实践情…

基于改进天鹰优化算法(IAO)优化RBF神经网络数据回归预测 (IAO-RBF)的数据回归预测(多输入多输出)

改进天鹰优化算法(IAO)见&#xff1a;【智能优化算法】改进的AO算法(IAO)-CSDN博客 代码原理 基于改进天鹰优化算法&#xff08;IAO&#xff09;优化RBF神经网络数据回归预测&#xff08;IAO-RBF&#xff09;的多输入多输出&#xff08;MIMO&#xff09;数据回归预测&#xf…

视频去水印软件?在线去除视频水印工具网站?

视频去水印软件哪个好&#xff1f;在数字时代&#xff0c;视频内容的传播变得日益普遍&#xff0c;然而&#xff0c;许多视频带有水印&#xff0c;影响了观看体验&#xff0c;如果有这些图案我们需要找方法把这些图案从视频上去掉。今天我们就来看一下视频去水印的超级简单的方…

添加阈值滞后以实现平滑的欠压/过压锁定

电阻分压器将高压衰减到低压电路可以承受的水平&#xff0c;而不会过驱动或损坏。在电源路径控制电路中&#xff0c;电阻分压器有助于设置电源欠压和过压锁定阈值。这种电源电压鉴定电路存在于汽车系统、电池供电的便携式仪器以及数据处理和通信板中。 欠压锁定 (UVLO) 可防止…

goLang小案例-打印99乘法表

goLang小案例-打印99乘法表 1. 打印99乘法表 func Print99multiplication1() {//横向9排for i : 1; i < 9; i {//竖向9列//第一批第一个 和第一列比较 如果大于排就结束//假设第三排i3 最走有三列 1*3 2*3 3*3//j3打印完 j 当j4就要结束 以此类推for j : 1; j < i; j …

蓝牙耳机推荐学生党怎么选?300左右蓝牙耳机分享

在选择蓝牙耳机时&#xff0c;学生党需要考虑的因素包括音质、续航力、舒适度以及连接稳定性等&#xff0c;而在300元左右的价位&#xff0c;虽然不能期待与高端产品相媲美的性能&#xff0c;但依然有一些性价比较高的选择能够满足大部分的日常需求&#xff0c;下面给大家推荐几…

使用python基于经纬度获取高德地图定位地址【逆地址解析】

一、高德地图api申请 1. 高德开放平台注册&#xff0c;登录 进入网址&#xff1a;高德开放平台 | 高德地图API 注册 -- 支付宝扫码认证 -- 完善个人信息 -- 登录 2. 申请API &#xff08;1&#xff09;点击头像 -- 应用管理 -- 我的应用 -- 创建新应用 &#xff08;2&…

【papaparse插件】前端预览csv文件

需求&#xff1a;就是可以在前端直接预览csv文件的内容 1.了解csv文件 1.1 csv文件和xlsx、xls文件的异同 首先了解一下csv文件和excel文件&#xff08;xlsx&#xff0c;xls&#xff09;有什么异同&#xff0c;简单来说他们都是存储表格数据的文件&#xff0c;csv只能显示较…

一站式AI服务平台:MaynorAI助您轻松驾驭人工智能

一站式AI服务平台&#xff1a;MaynorAI助您轻松驾驭人工智能 在当前的数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术已经成为推动各行各业创新发展的核心动力。为了更好地满足企业和个人用户对AI服务的需求&#xff0c;MaynorAI 作为一个领先的一站式调用国内…

【oracle】oracle索引分裂

本文为云贝教育 刘峰 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。 一、索引分裂概述 Oracle数据库中的索引分裂是数据库维护和性能管理中的一个重要概念&#xff0c;特别是在处理大量数据插入、更新和…

CVPR 2024最佳论文分享:生成图像动力学

CVPR 2024最佳论文分享&#xff1a;生成图像动力学 CVPR&#xff08;Conference on Computer Vision and Pattern Recognition&#xff09;是计算机视觉领域最有影响力的会议之一&#xff0c;主要方向包括图像和视频处理、目标检测与识别、三维视觉等。近期&#xff0c;CVPR 2…

2000—2022年青藏高原遥感生态指数数据集

该数据集是基于多套MODIS数据集&#xff0c;选取NDVI、LST、WET、NDBSI四项指标&#xff0c;采用主成分分析法&#xff0c;生成2000-2022年500米空间分辨率的遥感生态指数&#xff08;RSEI&#xff09;数据集。 遥感生态指数&#xff1a;是一种基于遥感技术的生态环境质量综合评…