LeetCode.203移除链表元素(原链表操作、虚拟头结点)

LeetCode.203移除链表元素

  • 1.问题描述
  • 2.解题思路
  • 3.代码

1.问题描述

给你一个链表的头节点 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

2.解题思路

以链表 1 4 2 4 来举例,移除元素4。

如果使用C,C++编程语言的话,不要忘了还要从内存中删除这两个移除的节点, 清理节点内存之后如图:

当然如果使用java ,python的话就不用手动管理内存了。(就算使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养成手动清理内存的习惯。)

那么:上述例子中,删除第一个4,只要将1的next指针直接指向下下个节点就好了。但这样,如果删除的是头结点就不好办了,于是两个办法。

  1. 直接使用原来的链表来进行删除操作。

    其余节点:用上述法子便行

    头结点:移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。

    所以只要将头结点向后移动一位就可以,这样就从链表中移除了一个头结点。依然别忘将原头结点从内存中删掉。

  2. 设置一个虚拟头结点在进行删除操作。

    这里来给链表添加一个虚拟头结点为新的头结点,此时要移除这个旧头结点元素1。就和移除链表其他节点的方式统一了。最后return 头结点的时候,别忘了 return dummyNode->next;, 这才是新的头结点

3.代码

C++:直接使用原来的链表来进行删除操作

#include <iostream>
using namespace std;struct ListNode {int val;ListNode* next;ListNode(int x): val(x), next(NULL) {}
};class Solution {public:ListNode* removeElements(ListNode* head, int val) {// 删除头结点值等于val的节点//为什么不用if,因为若输入为head = [1,1,1,1,1],应为一个持续移除的过程,所以为while//头结点不能为空,如果为空,相当于操作空指针了while(head != NULL && head->val == val) {//创建了一个临时指针tmp,它指向链表的头结点head。//这是为了保存需要被删除的节点,以便在将指针从链表中删除时,能够释放该节点所占用的内存。ListNode* tmp = head;head = head->next;delete tmp;  }ListNode* cur = head;//cur != NULL: 确保当前节点不为空。在删除节点时,我们需要更改节点的指针来连接正确的节点,//所以我们要确保cur指针不为空,避免访问空指针导致程序崩溃。//cur->next != NULL: 确保当前节点的下一个节点不为空。在删除节点时,//我们需要访问当前节点的下一个节点的值来进行比较,如果下一个节点为空,//则没有必要进行比较和删除操作while(cur != NULL && cur -> next != NULL) {if(cur->next->val == val) {ListNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;} else {cur = cur->next;}}return head;}
};int main() {ListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(6);head->next->next->next = new ListNode(3);head->next->next->next->next = new ListNode(4);head->next->next->next->next->next = new ListNode(5);head->next->next->next->next->next->next = new ListNode(6);int val = 6;Solution s;ListNode* res = s.removeElements(head, val);while (res != NULL) {cout << res->val << " ";res = res->next;}return 0;
}

C++:虚拟头结点

#include <iostream>
using namespace std;struct ListNode {int val;ListNode* next;ListNode(int x): val(x), next(NULL) {}//构造函数
};class Solution {public:ListNode* removeElements(ListNode* head, int val) {ListNode* dummyHead = new ListNode(0);//创建虚拟头节点dummyHead->next = head;//虚拟头节点指向头节点//临时指针从虚拟头节点开始遍历,如果直接用头结点进行遍历,那么头结点所指向的值是一直在改变的,最后无法返回了ListNode* cur = dummyHead;while(cur->next != NULL) {if(cur->next->val == val) {ListNode* tmp = cur->next;//暂存要删除的节点cur->next = cur->next->next;//删除节点delete tmp;//释放内存} else {cur = cur->next;//指向下一个节点}}head = dummyHead->next;//更新头节点  因为旧的head可能已经被删除了delete dummyHead;//释放虚拟头节点内存return head;//返回头节点}
};int main() {ListNode* node1 = new ListNode(1);ListNode* node2 = new ListNode(2);ListNode* node3 = new ListNode(6);ListNode* node4 = new ListNode(3);ListNode* node5 = new ListNode(4);ListNode* node6 = new ListNode(5);ListNode* node7 = new ListNode(6);node1->next = node2;node2->next = node3;node3->next = node4;node4->next = node5;node5->next = node6;node6->next = node7;Solution solve;ListNode* newhead = solve.removeElements(node1, 6); // 删除值为6的节点while(newhead != NULL) {cout << newhead -> val << " ";newhead = newhead -> next;}return 0;
}

python:虚拟头结点

class ListNode:def __init__(self, val, next=None):self.val = valself.next = nextclass Solution:def removeElements(self, head: ListNode, val: int) -> ListNode:dummyHead = ListNode()dummyHead.next = headcur = dummyHeadwhile cur.next:if cur.next.val == val:cur.next = cur.next.nextelse:cur = cur.nextreturn dummyHead.nexthead = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(6)
head.next.next.next = ListNode(3)
head.next.next.next.next = ListNode(4)
head.next.next.next.next.next = ListNode(5)
head.next.next.next.next.next.next = ListNode(6)sol = Solution()
new_head = sol.removeElements(head, 6)cur = new_headwhile cur:print(cur.val)cur = cur.next

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

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

相关文章

图书馆管理系统源码(Java)

Book包->内含Book类与BookList类 Book类 用于初始化图书并对其进行操作 BookList类 用于存放多本图书 Book类 package Book;public class Book {private String name;private String author;private int price;private String type;private boolean isBorrow;//写一个…

音频——S/PDIF

文章目录 BMC 编码字帧(sub-frame)格式帧(frame)格式参考S/PDIF 是 SONY 和 Philips 公司共同规定的数字信号传输规范,其实就是在 AES/EBU 上进行改动的家用版本。IEC60958 的标准规范囊括了以上两个规范。spdif 采用了双相符号编码(BMC),是将时钟信号和数据信号混合在一起…

强化学习,快速入门与基于python实现一个简单例子(可直接运行)

文章目录 一、什么是“强化学习”二、强化学习包括的组成部分二、Q-Learning算法三、迷宫-强化学习-Q-Learning算法的实现全部代码&#xff08;复制可用&#xff09;可用状态空间检查是否超出边界epsilon 的含义更新方程 总结 一、什么是“强化学习” 本文要记录的大概内容&am…

力扣:180. 连续出现的数字(Python3)

题目&#xff1a; 表&#xff1a;Logs ---------------------- | Column Name | Type | ---------------------- | id | int | | num | varchar | ---------------------- 在 SQL 中&#xff0c;id 是该表的主键。 id 是一个自增列。 找出所有至少连续…

Java 网络编程

文章目录 UDP Socket APIDatagramSocketDatagramPacket例子&#xff1a;UDP版本的回显服务器-客户端 TCP Socket APIServerSocketSocket例子&#xff1a;TCP版本的回显服务器-客户端 UDP Socket API DatagramSocket 这是一个 socket 类&#xff0c;本质上相当于一个文件&…

C3 多媒体查询

文章目录 前言CSS3 多媒体查询CSS2 多媒体类型CSS3 多媒体查询浏览器支持多媒体查询语法CSS3 多媒体类型多媒体查询简单实例 媒体类型媒体功能更多实例后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;CSS &#x1f431;‍&#x1f453;博…

SpringBoot 2 系列停止维护,Java8 党何去何从?

SpringBoot 2.x 版本正式停止更新维护&#xff0c;官方将不再提供对 JDK8 版本的支持 SpringBoot Logo 版本的新特性 3.2 版本正式发布&#xff0c;亮点包括&#xff1a; 支持 JDK17、JDK21 版本 对虚拟线程的完整支持 JVM Checkpoint Restore&#xff08;Project CRaC&…

Django之Auth模块

Auth模块引入 我们在创建一个Django项目之后&#xff0c;直接执行数据库迁移命令会自动生成很多表 django_sessionauth_userDjango在启动之后就可以直接访问admin路由&#xff0c;需要输入用户名和密码&#xff0c;数据参考的就是auth_user表,并且必须是管理员用户才能进入 【…

quickapp_快应用_某些css样式不兼容问题

样式问题 引入css样式文件[1] 单位px [2]选择器[3]盒模型[4]样式布局-默认弹性布局且不可取消[5-1]样式切换-类名的动态切换-语法[5-2]样式切换 - 类名的动态切换-目标元素[5-3] 样式切换 - 行内样式动态切换[6]background[7]overflow[8]border-radius[9]盒子阴影[10] 定位erro…

【调度算法】开放车间调度问题遗传算法(failed)

省流&#xff1a;这是一个错误的代码备份&#xff0c;如果你需要可以直接运行的完整代码&#xff0c;请移步GitHub。 本以为手搓了一个单机调度和并行机调度的遗传算法&#xff0c;就可以尝试写开放车间的遗传算法了&#xff0c;结果手搓了两天&#xff0c;开始作业时间和结束…

1、Mysql架构与历史

Mysql逻辑架构 最上层是服务并不是Mysql所独有的&#xff0c;大多数基于网络的客户端/服务器的工具或者服务都有类似的架构&#xff0c;比如连接处理&#xff0c;授权认证&#xff0c;安全等。 第二层是Mysql比较有意思的部分。大多数Mysql的核心服务都在这一层&#xff0c;…

torch.view()和.reshape()

view只能作用在连续的张量上&#xff08;张量中元素的内存地址是连续的&#xff09;。而reshape连续or非连续都可以。 调用x.reshape的时候&#xff0c;如果x在内存中是连续的&#xff0c;那么x.reshape会返回一个view&#xff08;原地修改&#xff0c;此时内存地址不变…

用户与组管理:如何在服务器系统中管理用户和权限

你是否想过&#xff0c;当你登录到一个服务器系统时&#xff0c;你是如何被识别和授权的&#xff1f;你是否知道&#xff0c;你可以通过创建和管理用户和组来简化和优化你的系统管理工作&#xff1f;你是否想了解一些常用的用户和组管理命令和技巧&#xff1f;如果你的答案是肯…

c语言实现简单的string

文章目录 前言一、注意事项二、代码valgrind扫描总结 前言 在c语言中利用面向对象的编程方式&#xff0c;实现类似c中的string类。 一、注意事项 所有与string结构体相关的函数全都没有返回值。 在c中&#xff0c;当产生临时对象时编译器会自动的加入析构函数&#xff0c;销毁…

Walrus 入门教程:如何创建模板以沉淀可复用的团队最佳实践

模板是 Walrus 的核心功能之一&#xff0c;模板创建完成后用户可以重复使用&#xff0c;并在使用过程中逐渐沉淀研发和运维团队的最佳实践&#xff0c;进一步简化服务及资源的部署。用户可以使用 HCL 语言自定义创建模板&#xff0c;也可以一键复用 Terraform 社区中上万个成熟…

云原生安全工具汇总(docker、k8s、Kubernetes、Git仓库)

目录 Metarget:云原生靶机环境 CDK:容器环境定制的渗透测试工具 container-escape-check:容器逃逸检测

synchronized在代码中的用法

synchronized可以对两种对象加锁&#xff1a;实例对象和类对象。下边先说对类对象加锁的代码&#xff1a; 第1是修饰static方法&#xff0c;第2种是直接锁类的class对象&#xff1b; /*** title: SynchronizedStaticDemo1* description: synchronized 对类加锁1* author: * d…

【Python百宝箱】Python数据探险:Excel与数据科学的完美结合

前言 在当今信息爆炸的时代&#xff0c;数据处理和分析已经成为各行各业不可或缺的一部分。在众多数据处理工具中&#xff0c;Python以其简洁而强大的语法成为数据科学家和分析师的首选之一。本文将深入探讨与电子表格处理相关的Python库&#xff0c;介绍它们的功能、应用场景…

批量按顺序1、2、3...重命名所有文件夹里的文件

最新&#xff1a; 最快方法&#xff1a;先用这个教程http://文件重命名1,2......nhttps://jingyan.baidu.com/article/495ba841281b7079b20ede2c.html再用这个教程去空格&#xff1a;利用批处理去掉文件名中的空格-百度经验 (baidu.com) 以下为原回答 注意文件名有空格会失败…

LeetCode Hot100 105.从前序与中序遍历序列构造二叉树

题目&#xff1a;给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 代码&#xff1a; class Solution {private Map<Integer, Integer> indexM…