移除链表元素(最优解)

server/2024/12/23 1:27:23/

题目来源

203. 移除链表元素 - 力扣(LeetCode)


题目描述

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

示例 1:

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

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

题目限制

题目用最优解实现求解


思路分析

一、整体思路概述

解决这个问题的核心思路是遍历整个链表,在遍历过程中判断每个节点的值是否等于给定的 val,如果相等,则将该节点从链表中删除,最终返回处理后的链表头节点。不过,在实际操作过程中,为了便于统一处理逻辑,尤其是应对要删除的节点可能是链表头节点这种特殊情况,我们通常会采用添加 “虚拟头节点” 的技巧来简化代码实现。

二、具体步骤与思路解析

(一)处理边界情况(空链表)

首先需要考虑一种特殊的边界情况,那就是当传入的链表本身就是空链表时(即 head 为 nullptr),这种情况下没有节点可供删除操作,直接返回原链表的头节点 head 就可以了,因为空链表无需做任何修改,保持原样返回就是正确的处理方式。

(二)添加虚拟头节点

为了让链表的删除操作逻辑更加简洁统一,我们创建一个新的节点作为虚拟头节点,例如:ListNode* dummy = new ListNode(-1);(这里给虚拟头节点赋的值 -1 只是一个示例,具体值不影响操作逻辑,只要便于区分就行),然后让这个虚拟头节点的 next 指针指向原来链表的头节点,即 dummy->next = head;

此时,我们后续的操作就可以从这个虚拟头节点开始遍历链表了,这么做的好处在于,当需要删除的节点恰好是原链表的头节点时,我们无需单独写额外的逻辑去处理头节点的删除情况,而是可以和删除其他普通节点一样,按照统一的逻辑进行处理,大大简化了代码的复杂度和逻辑判断。

(三)遍历链表并删除指定值的节点

接下来就是通过循环来遍历整个链表,以实现对每个节点值的检查以及相应的删除操作。常用的做法是使用一个指针(设为 cur),初始时让它指向我们创建的虚拟头节点,然后通过 while(cur->next) 这样的循环条件来进行循环,只要 cur 指针指向的当前节点的下一个节点存在(即 cur->next 不为 nullptr),就继续循环去检查后续的节点。

在循环体内部,我们需要对当前节点(也就是 cur 指针指向的节点)的下一个节点(通过 cur->next 访问)的值进行判断。如果发现 cur->next->val == val,这就意味着找到了一个需要删除的节点,此时我们通过改变指针的指向来实现节点删除,具体操作就是让 cur 指针的 next 指针跳过这个要删除的节点,直接指向它的下下个节点,即 cur->next = cur->next->next;,这样就相当于把值为 val 的这个节点从链表中移除掉了,实际是改变了链表的内部指针连接关系,使得该节点不再属于链表的一部分。

如果当前节点的下一个节点的值不等于 val,那就说明这个节点不需要被删除,此时我们只需要让 cur 指针往后移动一位,即 cur = cur->next;,继续去检查下一个节点的情况就可以了。

(四)返回处理后的链表头节点

经过前面的遍历和节点删除操作后,最后我们需要返回处理后的链表的头节点。由于之前添加了虚拟头节点,所以真正的链表头节点现在是由虚拟头节点的 next 指针指向的,因此我们直接返回 dummy->next 就可以得到经过处理后的链表的正确头节点了,这个头节点指向的链表就是已经删除了所有值为 val 的节点后的新链表。

三、总结

通过以上步骤,我们利用添加虚拟头节点的技巧,配合循环遍历和指针操作,统一且有条理地实现了删除链表中所有满足特定值节点的功能。这种思路在处理链表相关问题,尤其是涉及节点删除、插入等操作时经常会用到,希望大家通过对这道题思路的详细分析,能够更好地掌握链表操作的技巧,灵活应对类似的编程挑战呀


具体代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeElements(ListNode* head, int val) {if(!head)return head;ListNode* cur=new ListNode(-1);cur->next=head;ListNode* pre=cur;while(cur->next){if(cur->next->val==val)cur->next=cur->next->next;else cur=cur->next;}return pre->next;}
};

在单链表操作中,常常会遇到依据特定值移除链表中节点的需求。下面这段 C++ 代码实现了给定一个单链表头节点指针 head 以及一个整数 val,将链表中所有值为 val 的节点移除的功能。

首先是边界情况处理,if(!head) return head; 这句代码考虑到了传入的链表为空(即 head 为 nullptr)的情况,此时无需操作,直接返回原 head 即可。

接着创建了一个虚拟头节点 ListNode* cur = new ListNode(-1);,并让其 next 指针指向真正的链表头节点 cur->next = head;,同时定义 ListNode* pre = cur;,这里的虚拟头节点作用很大,能统一后续移除节点的逻辑,避免对头节点单独判断。

核心的移除节点操作在 while(cur->next) 循环里,只要当前节点(cur 指向)的下一个节点存在就继续循环。循环体中通过 if - else 判断,若 cur->next->val == val,执行 cur->next = cur->next->next,即跳过值为 val 的节点,改变链表指针连接实现 “删除”;若不符合条件,则执行 cur = cur->next,继续检查下一个节点。

最后通过 return pre->next; 返回经过处理后的链表头节点,因为添加了虚拟头节点,真正的链表头就在 pre 的 next 指针指向处。总之,这段代码借助虚拟头节点,以清晰的逻辑和简洁的方式实现了单链表中指定值节点的移除功能,实用性很强哦。


http://www.ppmy.cn/server/152372.html

相关文章

【ETCD】【源码阅读】深入分析 applierV3backend.Apply`方法源码

applierV3backend的Apply主要负责将 Raft 请求 (pb.InternalRaftRequest) 应用到 Etcd 的后端存储中。它处理各种不同类型的请求&#xff0c;并且根据请求的具体内容调用相应的处理逻辑。 版本【release 文章目录 一、完整源码二、方法详解1. 定义和初始化2. 记录操作开始时间并…

Docker搭建kafka环境

系统&#xff1a;MacOS Sonoma 14.1 Docker版本&#xff1a;Docker version 27.3.1, build ce12230 Docker desktop版本&#xff1a;Docker Desktop 4.36.0 (175267) 1.拉取镜像 先打开Docker Desktop&#xff0c;然后在终端执行命令 docker pull lensesio/fast-data-dev …

ios的safari下载文件 文件名乱码

当使用nginx代理文件并下载文件时&#xff0c;返回的协议头Content-Disposition中filename%E9%9B%AA%E5%B1%B1.jpg中文内容会是URL编码的形式&#xff0c;当客户端在safari浏览器下载下载文件时&#xff0c;文件名不会转换&#xff08;URL解码&#xff09;为正常的中文。 应该…

全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(关系运算符和逻辑运算符)

在C编程的旅途中&#xff0c;经常会遇到需要根据不同条件执行不同代码的情况。这时&#xff0c;分支结构就显得尤为重要。它就像程序中的“决策点”&#xff0c;让程序能够根据输入、状态或其他条件智能地选择执行路径。这时就需要学习关系表达式与逻辑表达式&#xff0c;有了判…

Altair: 轻松创建交互式数据可视化

Altair: 轻松创建交互式数据可视化 Altair 是一个基于 Vega-Lite 的 Python 数据可视化库&#xff0c;它旨在简化数据可视化的创建过程&#xff0c;尤其适用于统计图表的生成。Altair 强调声明式编码方式&#xff0c;通过简单的语法&#xff0c;用户能够快速创建复杂的交互式图…

使用JavaScript获取商品详情接口:一个实用的指南

引言 在现代电子商务中&#xff0c;获取商品详情是提供个性化购物体验的关键。JavaScript&#xff0c;作为一种广泛使用的编程语言&#xff0c;可以轻松地与各种API进行交互&#xff0c;从而获取商品信息。本文将指导您如何使用JavaScript调用商品详情接口&#xff0c;并处理返…

基于Spring Boot的个人财务系统

一、系统背景与目的 随着全球经济的发展和人们生活水平的提高&#xff0c;个人财务管理变得越来越重要。传统的个人财务软件存在操作复杂、用户体验差、数据不安全等问题&#xff0c;无法满足用户的个性化需求。因此&#xff0c;开发一种基于Spring Boot的个人财务系统&#x…

探秘数据库索引:功能、意义与实例

探秘数据库索引&#xff1a;功能、意义与实例 ​数据库索引就像是一个 “路标” 或者 “地图”。当进行查询操作时&#xff0c;数据库软件首先会查找索引表。索引表中的数据是经过排序的&#xff0c;并且和原表中的数据存在关联&#xff08;这种关联可以是基于数据行的物理位置…