代码随想录算法训练营第三天| 203.移除链表元素、 707.设计链表、 206.反转链表

203.移除链表元素

在这里插入图片描述

题目链接: 203.移除链表元素
文档讲解:代码随想录
状态:没做出来,做题的时候定义了一个cur指针跳过了目标val遍历了一遍链表,实际上并没有删除该删的节点。

错误代码:

    public ListNode removeElements(ListNode head, int val) {ListNode sentinel = new ListNode();sentinel.next = head;ListNode cur = sentinel;while (cur.next != null) {ListNode next = cur.next;if (next.val == val) {// 这里是错误的,cur 被设置为 next.next,直接跳过了 next 节点。但这并没有实际从链表中删除 next 节点,它仍然存在于链表中。// 如果 next.next 是 null,则 cur 被设置为 null,导致后续的 cur.next 会抛出空指针异常cur = next.next;} else {cur = next;}}return sentinel.next;}

思路:定义一个ListNode类型的cur指针,遍历链表,遇到等于目标val的节点,通过修改节点的next实现删除元素。因为NodeList是引用类型,所以当cur从虚拟头节点出发时,修改cur中的引用会影响虚拟头节点后面的值,从而实现删除操作。

题解

    public ListNode removeElements(ListNode head, int val) {// 创建一个哨兵节点,简化边界情况的处理ListNode sentinel = new ListNode();sentinel.next = head;ListNode cur = sentinel;// 遍历链表while (cur.next != null) {ListNode next = cur.next;// 如果下一个节点的值等于指定值if (next.val == val) {// 应该通过修改cur.next来删除next节点cur.next = next.next;} else {// 否则,继续向后遍历cur = next;}}// 返回处理后的链表头节点return sentinel.next;}

什么时候使用虚拟头节点?
虚拟头节点(哨兵节点)主要解决了由于头节点可能为空或者需要特别处理而导致的额外操作。
如果在使用虚拟头节点后仍然从 head 节点出发,那么虚拟头节点的定义就失去了意义。

所以,当定义了虚拟头节点(哨兵节点)后,一般情况下,遍历操作中的 cur(当前节点)都从虚拟头节点出发。这是因为虚拟头节点是为了简化处理头节点的特殊情况而引入的,从虚拟头节点开始遍历,可以统一处理所有节点(包括原本的头节点),避免了额外的边界条件检查。

707.设计链表

在这里插入图片描述

题目链接:707.设计链表
文档讲解:代码随想录
状态:没做出来(使用了双向链表,没有使用虚拟头节点,结果一堆边界问题。。。)

题解

单向链表+虚拟头节点题解

public class MyLinkedList {private ListNode dummy; // 虚拟节点private int size;       // 链表的长度/** 初始化链表 */public MyLinkedList() {dummy = new ListNode(0);size = 0;}/** 获取链表中下标为 index 的节点的值,如果下标无效则返回 -1 */public int get(int index) {if (index < 0 || index >= size) {return -1;}ListNode current = dummy.next;for (int i = 0; i < index; i++) {current = current.next;}return current.val;}/** 在链表头部插入值为 val 的节点 */public void addAtHead(int val) {ListNode newHead = new ListNode(val);newHead.next = dummy.next;dummy.next = newHead;size++;}/** 在链表尾部追加值为 val 的节点 */public void addAtTail(int val) {ListNode newTail = new ListNode(val);ListNode current = dummy;while (current.next != null) {current = current.next;}current.next = newTail;size++;}/** 在链表中下标为 index 的节点之前插入值为 val 的节点 */public void addAtIndex(int index, int val) {if (index < 0 || index > size) {return;}
// 注意:不是ListNode current = dummy.next;
// 简而言之,ListNode cur = dummy; 确保了在插入节点时,从链表的头节点开始遍历,而不是跳过头节点。
// 例如index=0,则是dummy.next = newNodeListNode current = dummy;for (int i = 0; i < index; i++) {current = current.next;}ListNode newNode = new ListNode(val);newNode.next = current.next;current.next = newNode;size++;}/** 删除链表中下标为 index 的节点 */public void deleteAtIndex(int index) {if (index < 0 || index >= size) {return;}ListNode current = dummy;for (int i = 0; i < index; i++) {current = current.next;}current.next = current.next.next;size--;}static class ListNode {int val;ListNode next;// 节点构造函数public ListNode(int val) {this.val = val;}}
}

双向链表无虚拟头节点题解(不推荐)

class MyLinkedList {ListNode head;static class ListNode {int val;ListNode pre;ListNode next;public ListNode() {}public ListNode(int val, ListNode pre, ListNode next) {this.val = val;this.pre = pre;this.next = next;}@Overridepublic String toString() {return "ListNode{" +"val=" + val +", pre=" + pre +", next=" + next +'}';}}public MyLinkedList() {head = null;}public int get(int index) {if (index < 0 || head == null) {return -1;}ListNode cur = head;while (index > 0 && cur != null) {cur = cur.next;index--;}return (cur == null) ? -1 : cur.val;}public void addAtHead(int val) {ListNode node = new ListNode(val, null, head);if (head != null) {head.pre = node;}head = node;}public void addAtTail(int val) {ListNode node = new ListNode(val, null, null);ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = node;node.pre = cur;}public void addAtIndex(int index, int val) {if (index < 0) {return;}if (index == 0) {addAtHead(val);return;}ListNode cur = head;while (index > 1 && cur != null) {cur = cur.next;index--;}if (cur == null) {return;}ListNode node = new ListNode(val, cur, cur.next);if (cur.next != null) {cur.next.pre = node;}cur.next = node;}public void deleteAtIndex(int index) {if (index < 0 || head == null) {return;}if (index == 0) {head = head.next;if (head != null) {head.pre = null;}return;}ListNode cur = head;while (index > 0 && cur != null) {cur = cur.next;index--;}if (cur == null) {return;}if (cur.pre != null) {cur.pre.next = cur.next;}if (cur.next != null) {cur.next.pre = cur.pre;}}
}

206.反转链表

在这里插入图片描述

题目链接: 206.反转链表
文档讲解:代码随想录
状态:没做出来,明明很简单的题,为啥没做出来呢。。。。。想着用dummy节点,dummy->1->2->3… dummy->2->1->3… dummy->3->2->1->…,这个dummy的next一直在变。。。

思路:

在这里插入图片描述

题解

    public ListNode reverseList(ListNode head) {// 初始化前一个节点为nullListNode prev = null;// 当前节点从head开始ListNode curr = head;while (curr != null) {// 暂时保存下一个节点ListNode next = curr.next;// 当前节点的next指向前一个节点curr.next = prev;// 移动前一个节点到当前节点prev = curr;// 移动当前节点到下一个节点curr = next;}// 最后prev将指向新的头节点return prev;}

总结反思

为啥做题的时候总是有很多乱七八糟的思路,自己找的还总是最差的那种呢。。。。

链表题解的两个技巧
遇到链表相关的题,无论问题是什么,先要想想是不是可以用上以下的两个技巧。

  1. 哨兵节点:哨兵节点是一个非常常用的链表技巧,在处理链表边界问题的场景下,可以减少我们代码的复杂度。
    主要解决的问题如下:
    • 处理完一条链表后,需要返回这个链表的头结点。我们在一开始的时候使用哨兵节点(dummy),让它的 next 节点指向 head 节点。最后 return 时直接返回 dummy.next 即可。
    • 在对链表进行插入或删除节点时,使用哨兵节点可以简化删除 head 节点或者向 head 前插入节点时的处理逻辑。因为头节点没有前驱节点,这就导致对其的增删需要额外操作。
    • 在某些遍历链表的时候,可能会需要同时记录 pre 节点。当你从 head 节点开始遍历时,head 是没有 pre 节点的(为null)。而此时引用哨兵节点,相当于帮助 head 节点初始化了一个 pre 节点,可以方便的解决 pre 节点为空的问题

为啥反转链表这道题不用虚拟头结点呢?

对于反转链表的操作,无论是递归还是迭代方法,都集中在反转节点的指针上,而不涉及节点的插入或删除操作。因此,反转链表的核心在于调整指针的方向,而不是处理节点的前驱节点或边界条件。这也是为什么在反转链表时,虚拟头节点并不能带来实际的简化。

  1. 双指针:其实不止是链表,对于数组题来说,也是非常好用的技巧。
    双指针的主要用法有以下几种:
    • 两个指针在两条链表上行走:这种方法通常用于合并两个有序链表、找到两个链表的交点等问题。
    • 快慢指针,同时前进:快慢指针通常用于检测链表中是否存在环,或者找到链表的中间节点等情况。
    • 前后指针,前指针先走 n 步,之后两个指针同时前进:这种方法常用于找到链表的倒数第 n 个节点,或者解决某些数组问题。
    • 一个指针用来迭代遍历链表,另一个指针用来记录:在链表操作中,常常需要用一个指针来迭代遍历链表,另一个指针用来记录节点,例如 pre 和 cur;cur 和 next;pre、cur 和 next。

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

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

相关文章

文档解析新纪元:TextIn产品体验与解决难题的深度剖析

前言 在数字化浪潮席卷各行各业的今天&#xff0c;作为一名数据分析师&#xff0c;每天我都需要处理和分析大量的文档。然而&#xff0c;传统的文档解析工具在面对我的专业需求时&#xff0c;往往显得力不从心。 我的工作常常涉及到各种格式的文档&#xff0c;包括PDF、Word、…

在洁净实验室设计装修中怎么选择合适实验室家具?

在现代科学研究和技术开发中&#xff0c;洁净实验室装修设计成为了确保实验准确性和安全性的重要因素。洁净实验室需要提供一个无尘、无菌、受控的环境&#xff0c;而在洁净实验室装修设计这个过程中&#xff0c;如何选择合适的实验室家具就显得尤为重要&#xff0c;因为它直接…

Web前端一套全部清晰 ⑨ day5 CSS.4 标准流、浮动、Flex布局

我走我的路&#xff0c;有人拦也走&#xff0c;没人陪也走 —— 24.5.24 一、标准流 标准流也叫文档流&#xff0c;指的是标签在页面中默认的排布规则&#xff0c;例如:块元素独占一行&#xff0c;行内元素可以一行显示多个。 二、浮动 作用: 让块级元素水平排列。 属性名:floa…

练习题(2024/5/22)

1N 皇后 II n 皇后问题 研究的是如何将 n 个皇后放置在 n n 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回 n 皇后问题 不同的解决方案的数量。 示例 1&#xff1a; 输入&#xff1a;n 4 输出&#xff1a;2 解释&#xff1a;如上…

民国漫画杂志《时代漫画》第18期.PDF

时代漫画18.PDF: https://url03.ctfile.com/f/1779803-1248612707-27e56b?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps:资源来源网络&#xff01;

春秋CVE-2022-23906

简介 CMS Made Simple v2.2.15 被发现包含通过上传图片功能的远程命令执行 (RCE) 漏洞。此漏洞通过精心制作的图像文件被利用。 正文 1.进入靶场2.进入登录界面&#xff0c;弱口令admin/123456 3.进入后台&#xff0c;文件上传点 4.上传一句话木马图片 5.复制图片&#xf…

细胞冻存——让你的细胞“长生不老”

《星际穿越》电影中提到漫长的太空旅程中&#xff0c;宇航员可以进入休眠水床休眠&#xff0c;并自行设定唤醒时间。在《异形》《深空失忆》《三体》等科幻作品中&#xff0c;都出现此类技术。《三体》中&#xff0c;休眠后来成为人类最普遍的一项技术。技术上的人类低温休眠&a…

OpenCV:入门(五)

图像梯度 图像梯度计算的是图像变化的速度。对于图像的边缘部分&#xff0c;其灰度值变化较大&#xff0c;梯度值也 较大&#xff1b;相反&#xff0c;对于图像中比较平滑的部分&#xff0c;其灰度值变化较小&#xff0c;相应的梯度值也较小。一般情 况下&#xff0c;图像梯度计…

中文信息期刊投稿邮箱

《中文信息》杂志是国家新闻出版总署批准的国家级刊物&#xff08;月刊&#xff09;&#xff0c;国内外公开发行&#xff0c;大十六开印刷。本刊主要反映我国中文信息处理的学术水平&#xff0c;重点刊登科技、经济、教育等领域的基础理论、科研与应用技术的学术论文&#xff0…

第2天 搭建安全拓展_小迪网络安全笔记

1.常见搭建平台脚本使用: 例如 phpstudy IIS Nginx(俗称中间件): 什么是中间件: 中间件是介于应用系统和系统软件之间的一类软件&#xff0c;它使用系统软件所提供的基础服务&#xff08;功能&#xff09;&#xff0c;衔接网络上应用系统的各个部分或不同的应用&#…

vue2引入brand.vue和brand-add-or-update.vue后重启项目报错解决方案

最近在用粒谷商城项目练手&#xff0c;学习到P59时引入品牌两个vue文件&#xff0c;重启(npm run dev)项目报错: ERROR Failed to compile with 2 errors 12:11:59Th…

【论文阅读】Rank-DETR(NIPS‘23)

paper:https://arxiv.org/abs/2310.08854 code:https://github.com/LeapLabTHU/Rank-DETR

微信小程序视频怎么保存到本地

你是否遇到过在微信小程序中发现了精彩的视频&#xff0c;却不知道如何将其保存到本地的困扰&#xff1f;别担心&#xff0c;这篇文章将为您揭示2024年最新的保存方法&#xff0c;让您轻松下载和保留这些珍贵的视频内容。不管您是使用安卓设备还是苹果设备&#xff0c;我们都为…

学生手机管理方案

咱们现在的学生&#xff0c;手机几乎成了标配。所以问题就来了&#xff0c;怎么管理这些手机&#xff0c;让手机在课堂上不成为学习的干扰&#xff1f; 先得搞明白&#xff0c;手机在学生手里上该扮演什么角色。手机确实能帮学生查资料、交流学习&#xff0c;甚至写作业&#x…

Log360:护航安全,远离暗网风险

暗网有时候就像是一个神秘的地下世界&#xff0c;是互联网的隐蔽角落&#xff0c;没有任何规则。这是一个被盗数据交易、网络犯罪分子策划下一步攻击的地方。但仅仅因为它黑暗&#xff0c;不意味着你要对潜在的威胁视而不见。 暗网 这就是ManageEngine Log360的用武之地&…

【Oracle篇】rman工具实用指南:常用命令详解与实践(第二篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

【Centos7+JDK1.8】Jenkins安装手册

一、安装环境 Centos7 JDK1.8 Jenkins-2.346.3 JDK1.8安装以及网络配置等 自行搜索资料解决。 二、卸载历史安装的Jenkins&#xff0c;直接全部复制粘贴下面的命令 service jenkins stop yum -y remove jenkins rpm -e jenkins rpm -ql jenkins rm -rf /etc/sysconfig/je…

解决远程链接的“Gtk-WARNING **: cannot open display;

1.需要检查ssh配置中X11Forwarding是否启用 2.检查本地ssh工具是否启用x11转发&#xff08;下图以mobaxterm为例&#xff09; 3.检查是否有防火墙等其他网络拦截&#xff0c;如果没有特殊需求&#xff0c;这里可以直接将防火墙服务关闭 4.按上诉操作检查后&#xff0c;正常情况…

P2P服务端模型配合 Tool.net P2pServerAsync 类使用

Tool.Net 支持的 P2P 服务器模型实例 说明服务器部分相关代码相关调用实例Tcp版本Udp版本 最后附一张思维图 说明 当前文章&#xff0c;仅是Tool.Net 开源库的一个缩影。本次更新V5.0版本以上提供支持。可以提供简单实现P2P功能用于业务开发。 服务器部分相关代码 完整代码&…

JVM运行时内存:垃圾回收器(Serial ParNew Parallel )详解

文章目录 1. 查看默认GC2. Serial GC : 串行回收3. ParNew GC&#xff1a;并行回收4. Parallel GC&#xff1a;吞吐量优先 1. 查看默认GC -XX:PrintCommandLineFlags&#xff1a;查看命令行相关参数&#xff08;包含使用的垃圾收集器&#xff09;使用命令行指令&#xff1a;ji…