LeetCode算法题 (移除链表元素)Day15!!!C/C++

https://leetcode.cn/problems/remove-linked-list-elements/description/

一、题目分析

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

        今天的题目非常好理解,也就是要删除掉链表中==val的值,并返回新的头节点。

二、相关知识了解

        链表这种数据结构其实与数组相似,同属线性表,但是与数组相比的话,链表是不支持随机访问元素的,也就是说要想在链表中查询一个元素的位置的话,时间复杂度最坏为O(n)如果要查找的元素位于链表末尾(或不存在),需要遍历整个链表,遍历次数为n次。)。平均也就是O((n + 1)/ 2)(这里就不过多的推导了,感兴趣的同学可以期待一下下一期的题目,我会详细带着大家一起设计出一个功能相对完善的链表

对比数组的随机访问

  • 数组支持随机访问(通过下标),查询时间为 O(1),这是链表与数组的核心差异之一。

  • 但链表在插入/删除节点(尤其头部)时更高效 O(1),而数组可能需要移动元素(O(n))。

三、示例分析

输入: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
输出:[]

四、解题思路&代码实现

        方法一:原链表删除元素(复杂度为O(n))

           首先,拿到一个链表第一步我们要进行的是判断该链表是否为空,如果为空的话直接return head就好。其次就是判断当前节点的值是否==val。如果==的话那么就需要对该节点进行删除操作。下面看一下具体代码的实现。

class Solution {
public:ListNode* removeElements(ListNode* head, int val) {// 处理头节点等于val的情况(可能需要连续删除多个头节点 如示例3)while (head && head->val == val) {ListNode* temp = head;  // 临时保存当前头节点head = head->next;      // 头节点指向下一个节点delete temp;           // 释放原头节点的内存}// 遍历链表,删除非头节点中值等于val的节点ListNode* cur = head;       // 当前节点指针while (cur && cur->next) {  // 当前节点和下一个节点均非空时循环if (cur->next->val == val) {// 如果下一个节点值等于val,则删除它ListNode* temp = cur->next;  // 临时保存待删除节点cur->next = cur->next->next;  // 跳过待删除节点,直接连接下下个节点delete temp;                  // 释放待删除节点的内存} else {// 否则,移动到下一个节点继续检查cur = cur->next;}}return head;  // 返回处理后的链表头节点}
};

        这里需要注意几个关键点:

  1. 首先在C/C++中堆区开辟的空间需进行手动释放,以免造成空间浪费,或者该空间内的脏数据影响程序结果。(一定要养成良好的编程习惯)
  2. 在第二个while语句终止条件中,一定要cur和cur->next都不为空时我们再去进行循环体,确保不会访问到空指针。最终返回的head节点有可能为NULL,也就是示例3的情况。
  3. 在进行头节点的处理使用while处理连续多个头节点值等于 val 的情况而不是if(if只能处理一次(例如 [1,1,1,2] 删除 1)。每次删除节点时记得更新head节点,并使用delete释放内存
  4. 如果 cur->next 的值等于 val,则修改 cur->next 跳过该节点,并释放内存。如果不等,则正常移动到下一个节点。

        方法二:虚拟头节点法(复杂度为O(n))

          虚拟头节点法属于是对法一进行的一个优化操作,可以显著简化链表操作,尤其是在处理涉及头节点删除或修改的问题时。

        对比法一的优点:

  1. 无需特殊处理头节点,虚拟头节点始终作为链表的“前置节点”,使得真正的头节点(dummy->next)和其他节点的删除逻辑完全一致,避免分支判断。
  2. 简化代码的结构,法一需要进行两步操作,需先对头节点进行预处理操作,再去处理其余节点。而使用虚拟头节点则只需要一个循环即可处理所有节点,避免代码冗余从而简化代码。
  3. 虚拟头节点确保 cur 初始指向一个非空节点(dummy),因此 cur->next 的访问总是安全的(无需额外判空)。

        具体实现代码如下:

class Solution {
public:ListNode* removeElements(ListNode* head, int val) {// 创建虚拟头节点(dummy node),其值任意(这里设为0),next指向原链表头节点// 使用虚拟头节点可以统一处理原头节点和其他节点的删除逻辑ListNode* dummy = new ListNode(0);dummy->next = head;  // 将虚拟头节点连接到原链表// cur指针用于遍历链表,初始指向虚拟头节点ListNode* cur = dummy;// 遍历链表,检查每个节点的下一个节点(cur->next)while (cur->next) {if (cur->next->val == val) {  // 如果下一个节点的值等于目标值ListNode* temp = cur->next;  // 临时保存要删除的节点cur->next = cur->next->next; // 跳过要删除的节点,直接连接下下个节点delete temp;                 // 释放要删除节点的内存(避免内存泄漏)// 注意:这里不移动cur指针,因为新的cur->next可能也需要删除// 例如链表[1,2,2,3],删除2时需要连续检查} else {cur = cur->next;  // 如果不需要删除,则正常移动到下一个节点}}// 返回处理后的链表头节点(即dummy->next)// 注意:原头节点可能已被删除,dummy->next会自动更新为新的头节点ListNode* newHead = dummy->next;delete dummy;  // 释放虚拟头节点的内存return newHead;}
};

        关键点说明:

  1. 虚拟头节点:创建一个虚拟头节点作为原链表的起始点,其next指针指向的为原链表的head节点 (作用:统一处理逻辑,避免单独进行头节点删除操作)
  2. 返回值:这里需要注意我们需要返回的值应为虚拟头节点的next,若原链表所有节点都已被删除,那么虚拟头节点的next会变为NULL,则无需处理。

        其余与方法一相同!

至此算法已经是最优解!完结撒花!!!🌸🌸🌸

四、题目总结     

方法一:原链表删除元素

此方法先对头节点进行处理,若头节点的值等于 val,则连续删除头节点直至其值不等于 val。之后遍历链表,对非头节点中值等于 val 的节点进行删除操作。该方法时间复杂度为 O(n),不过在处理头节点时需要额外的逻辑判断,且要分别处理头节点和非头节点的删除情况,代码相对复杂。

方法二:虚拟头节点法

这种方法创建了一个虚拟头节点,将其 next 指针指向原链表的头节点。通过遍历链表,检查每个节点的下一个节点,若其值等于 val 则进行删除。此方法的优点在于统一了头节点和其他节点的删除逻辑,避免了额外的分支判断,简化了代码结构。时间复杂度同样为 O(n),是对方法一的优化。

总结

在处理链表删除操作时,使用虚拟头节点能有效简化代码,避免因头节点的特殊情况而增加的复杂逻辑,提高代码的可读性和可维护性。两种方法的时间复杂度均为线性,已达到最优解。在实际编程中,要养成手动释放堆区内存的习惯,防止内存泄漏。今天的题解分享到这里,谢谢大家!!!荆轲刺秦!!!

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

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

相关文章

Scrapy框架之【Scrapy-Redis】分布式爬虫详解

Scrapy-Redis 介绍 Scrapy-Redis 是一个基于 Redis 实现的 Scrapy 分布式爬虫组件。Scrapy 本身是一个强大的 Python爬虫框架,但它默认是单进程单线程的,在面对大规模数据抓取任务时效率不高。Scrapy-Redis 则解决了这一问题,它允许你将 Scra…

Gradio全解20——Streaming:流式传输的多媒体应用(3)——实时语音识别技术

Gradio全解20——Streaming:流式传输的多媒体应用(3)——实时语音识别技术 本篇摘要20. Streaming:流式传输的多媒体应用20.3 实时语音识别技术20.3.1 环境准备和开发步骤1. 环境准备2. ASR应用开发步骤(基于Transform…

使用xlwings将两张顺序错乱的表格进行数据核对

有如下一个excel表,姓名列的内容相同,顺序不同;月薪有部分内容不同。 目的:要找出哪几条月薪不同。 通常的做法,要使用excel的高级筛选。 在此,使用xlwings实现,在不同的内容上涂色。 代码如…

2025大模型安全研究十大框架合集(10份)

2025大模型安全研究十大框架合集的详细介绍: Anthropic AI信任研究框架 Anthropic于2024年10月更新的《安全责任扩展政策》(RSP),提出了一个灵活的动态AI风险治理框架。该框架规定当AI模型达到特定能力时,将自动升级安全措施,如…

Qt/C++开发监控GB28181系统/云台控制/获取预置位信息/添加删除调用预置位

一、前言 之前用onvif已经完美实现了设备的云台控制和预置位的功能,这个基础功能在监控系统中是使用频率很高的,所有gb28181肯定也提供了这样的功能,很多人以为是通过包含xml数据,对应节点指定对应的动作来实现,其实不…

第T8周:猫狗识别

● 语言环境:Python3.8.8 ● 编译器:Jupyter Lab ● 深度学习环境:TensorFlow2.4.1 猫狗识别 一、前期工作1. 设置GPU 二、数据预处理1. 加载数据2.再次检查数据3.配置数据集 三、构建VG-16网络四、编译五、训练模型六、模型评估七、预测八、…

主流微前端框架比较

主流微前端框架比较 以下表格列出了当前主流微前端框架的核心对比信息,包括基本介绍、核心特性、适用场景、技术栈兼容性、优缺点、社区维护情况和典型应用案例等: 框架基本介绍核心特性与机制适用场景技术栈兼容性优缺点社区维护情况典型应用案例qiankun蚂蚁金服推出的生产…

大学生入学审核系统设计与实现【基于SpringBoot + Vue 前后端分离技术】

一、项目概述 1.1 项目背景 随着高校的不断扩招,传统的入学审核管理模式已不能满足大规模学生数据的处理需求。人工管理不仅效率低下,还容易出现疏漏。本系统通过信息化手段,提升入学审核过程中的数据管理和审批效率。 1.2 系统目标 系统…

云计算-容器云-服务网格Bookinfo

服务网格:创建 Ingress Gateway 将 Bookinfo 应用部署到 default 命名空间下,请为 Bookinfo 应用创建一个网 关,使外部可以访问 Bookinfo 应用。 上传ServiceMesh.tar.gz包 [rootk8s-master-node1 ~]# tar -zxvf ServiceMesh.tar.gz [rootk…

Spring 分批处理 + 冷热数据分离:历史订单高效迁移与数据清理实战

在实际业务中,随着时间推移,订单量持续增长,若未及时进行数据治理,会造成数据库膨胀、查询缓慢、性能下降等问题。为了实现数据分层管理和系统高性能运行,我们在项目中采用了“冷热数据分离 分批迁移 数据清理”的综…

新手SEO优化核心步骤

内容概要 对于SEO新手而言,建立系统化的优化框架是突破入门瓶颈的关键。SEO的核心在于通过技术手段与内容策略的结合,提升网站在搜索引擎中的可见性与用户价值。具体而言,新手需优先掌握关键词研究,明确目标用户的搜索意图&#…

C++ 之 【list的简介、list 的构造函数、iterator、容量操作、元素访问、增删查改与迭代器失效】

目录 1.list的介绍 2.list的使用 2.1 构造函数 2.2 iterator 的使用 2.3 容量操作 2.4 元素访问 2.5 增删查改 2.5.1头插头删与尾插尾删 2.5.2 insert 、erase 函数 2.5.3 clear、swap函数 2.5.4 关于find函数 3.迭代器失效 1.list的介绍 (1)list的底层通常实现为带…

Laravel Octane 项目加速与静态资源优化指南

Laravel Octane 项目加速与静态资源优化指南 一、Octane 核心加速配置 扩展安装与环境配置 composer require laravel/octane # 安装核心扩展‌php artisan octane:install # 生成配置文件(选择 Swoole/RoadRunner 等服务器)‌服务器参数调优‌ …

高露洁牙膏是哪个国家的品牌?高露洁牙膏哪一款最好?

高露洁是来自于美国一个比较有知名度的品牌,在1806年的时候创立。总部是在美国纽约公园大道,在1873年时,高露洁就已经开始销售罐装牙膏。 在1896年时期推出可折叠管牙膏,在口腔护理产品发展的过程中拥有着不容忽视的地位。在1992…

【Python爬虫详解】第八篇:突破反爬体系的工程实践

当矛与盾的较量进入白热化,突破反爬需要的不只是技巧,更是一套完整的工程化解决方案——本文将揭示对抗现代反爬体系的九大核心战术。 一、JavaScript混淆的深度破解 1. AST(抽象语法树)解混淆 案例:某电商平台商品价…

【Linux调整FTP端口】

Linux调整FTP端口 一、确保新端口未被占用在修改端口之前,可以使用以下命令检查端口是否被占用: 二、修改vsftpd配置文件1. 打开vsftpd配置文件2. 找到并修改端口配置3. 保存并退出4. 重启vsftpd服务 三、配置防火墙 在Linux系统中修改FTP端口&#xff0…

npm打包内存不足- JavaScript heap out of memory

直接贴出报错信息 <--- Last few GCs --->[30904:0000010F60FE58E0] 22090 ms: Scavenge 2037.4 (2069.4) -> 2036.4 (2074.2) MB, 2.5 / 0.0 ms (average mu 0.228, current mu 0.216) allocation failure [30904:0000010F60FE58E0] 22101 ms: Scavenge 2…

AI大语言模型破译“未知未知”的密钥:开源情报、被动收入与智能体协作的深层机理与实践

在人类认识世界的漫长征程中&#xff0c;信息与知识的获取和运用一直是核心驱动力。我们从“一无所知”的状态&#xff0c;逐渐积累“已知已知”&#xff0c;并在此基础上识别“已知未知”&#xff0c;设定目标去探索解答。然而&#xff0c;真正能够带来范式转变、颠覆现有格局…

kubelet 清理资源以缓解磁盘压力

kubelet 资源清理缓解磁盘压力指南 在 Kubernetes 集群中&#xff0c;当节点磁盘压力过大时&#xff0c;可通过以下几种方式利用 kubelet 清理资源&#xff0c;从而缓解磁盘压力。 一、镜像垃圾回收 自动回收 kubelet 内置了镜像垃圾回收机制&#xff0c;其行为由配置参数控…

SPOJ 11576 TRIP2 - A Famous King’s Trip 【Tarjan+欧拉回路】

自我吐槽 &#xff08;哭 题目传送门 SPOJ 洛谷 题目大意 让你在简单无向图上删去2条边&#xff0c;使该图联通并存在欧拉回路 输出字典序最小的一对边 思路 考虑到存在欧拉回路的充要条件&#xff0c;即 i n x ≡ 0 ( m o d 2 ) ∀ i ( 1 ≤ i ≤ n ) in_x\equiv 0 (\m…