当前位置: 首页 > news >正文

代码随想录算法训练营第三天| 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。

相关文章:

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

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

【题解】AB33 相差不超过k的最多数(排序 + 滑动窗口)

https://www.nowcoder.com/practice/562630ca90ac40ce89443c91060574c6?tpId308&tqId40490&ru/exam/oj 排序 滑动窗口 #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {int n, k;cin >> n &…...

LSPatch免root手机模块应用

软件介绍 LSPatch是一款免root手机模块应用&#xff0c;兼容大部分机型&#xff0c;使用LSPatch&#xff0c;您可以个性化您的Android设备&#xff0c;添加新的功能&#xff0c;修改系统设置&#xff0c;甚至完全改变系统的外观。您可以根据自己的需求选择和安装各种Xposed模块…...

深入解析kube-scheduler的算法自定义插件

目录 ​编辑 一、问题引入 二、自定义步骤 三、最佳实践考虑 一、问题引入 当涉及到 Kubernetes 集群的调度和资源分配时&#xff0c;kube-scheduler 是一个关键组件。kube-scheduler 负责根据集群的调度策略&#xff0c;将 Pod 分配到适当的节点上。kube-scheduler 默认使…...

java原型模式 (Prototype Pattern) 介绍

原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;它通过复制现有的实例来创建新对象&#xff0c;而不是通过实例化类来创建对象。这个模式允许你创建对象时避免复杂的初始化步骤&#xff0c;并且能够动态地创建对象的副本。 原型模式的关键…...

LLama3 | 一. 本地 Web Demo 部署

前置工作 课程文档&#xff1a;Llama3-Tutorial/docs/hello_world.md at main SmartFlowAI/Llama3-Tutorial GitHub 1.安装vscode 2.安装vscode插件 Remote SSH 3.配置 VSCode 远程连接开发机 ssh连接开发机 进行端口映射 在开发机控制台中点击自定义服务&#xff0c;复…...

MariaDB 给指定列值自动加密(持久数据加触发器)

文章目录 代码插入时&#xff0c;自动加密更新时&#xff0c;自动加密查看触发器数据操作示例update数据取出解密取 注意一次尝试&#xff0c;看加密后数据长度 参考链接&#xff1a; 一篇非常好的讲解触发器的文章&#xff1a;示例、原理MySQL/MariaDB触发器。 用触发器自动加…...

深入理解Linux系统管理与网络配置高级指南

深入理解Linux系统管理与网络配置高级指南 目录 深入理解Linux系统管理与网络配置高级指南 一、Linux文件系统管理 二、Linux进程管理 三、Linux系统管理 四、Linux网络管理 五、Linux磁盘管理 一、Linux文件系统管理 1.1 文件和目录操作 在Linux中&#xff0c;一切皆…...

朴素贝叶斯+SMSSpamCollections

1. 打开 Jupyter 后&#xff0c;在工作目录中&#xff0c;新建一个文件夹命名为 Test01 &#xff0c;并且在文件夹中导入数据 集。在网页端界面点击 “upload” 按钮&#xff0c;在弹出的界面中选择要导入的数据集。然后数据集出现 在 jupyter 文件目录中&#xff0c;此时…...

【Android Studio】使用UI工具绘制,ConstraintLayout 限制性布局,快速上手

文章目录 一、前言二、绘制效果三、ConstraintLayout 使用方法3.1 创建布局文件3.2 替换配置3.3 设置约束&#xff0c;步骤13.4 设置约束&#xff0c;步骤23.5 其他设置 四、结束 一、前言 在进行Android APP开发过程中&#xff0c;减少layout嵌套即可改善UI的绘制性能&#x…...

深度神经网络详解

深度神经网络详解 一、引言二、深度神经网络的基本概念1. 什么是神经网络2. 深度神经网络的定义3. 基本结构4. 激活函数 三、深度神经网络的发展历史1. 初期发展2. 反向传播算法的提出3. 深度学习的崛起 四、深度神经网络的架构1. 前馈神经网络&#xff08;Feedforward Neural …...

MYSQL 数据迁移利器 MYSQLSH

1 迁移背景 将数据库从mysql5.7 迁移到mysql8.0. mysqlsh 支持mysql5.7以上版本。 2 查看数据量 SELECT TABLE_SCHEMA, round(SUM(data_length+index_length)/1024/1024,2) AS TOTAL_MB, round(SUM(data_length)/1024/1024,2) AS DATA_MB, …...

【MYSQL】分数排名

表: Scores ---------------------- | Column Name | Type | ---------------------- | id | int | | score | decimal | ---------------------- id 是该表的主键&#xff08;有不同值的列&#xff09;。 该表的每一行都包含了一场比赛的分数。Score 是…...

【论文笔记】| 蛋白质大模型ProLLaMA

【论文笔记】| 蛋白质大模型ProLLaMA ProLLaMA: A Protein Large Language Model for Multi-Task Protein Language Processing Peking University Theme: Domain Specific LLM Main work&#xff1a; 当前 ProLLM 的固有局限性&#xff1a;&#xff08;i&#xff09;缺乏自然…...

MySQL笔记第一天(从小白到入门)

文章目录 MySQL笔记SQL语言介绍数据库系统关系型数据库非关系型数据库SQL和数据库系统的关系数据库系统架构 MySQL的介绍概念MySQL的版本 MySQL的DDL操作-重点基本数据库操作基本表操作 MySQL的DML操作-重点insert-插入数据update-更新数据delete-删除数据 MySQL的约束-了解概述…...

初识Qt:从Hello world到对象树的深度解析

Qt中的对象树深度解析 Hello world1.图形化界面创建命令行式创建在栈上创建在堆上创建为什么传文本需要QString&#xff0c;std::string不行吗&#xff1f;那为什么要传入this指针&#xff1f;为什么new后不用显示调用delete函数呢&#xff0c;不会造成内存泄漏问题吗&#xff…...

多维数据库创建

多维数据库 小白的数据仓库学习笔记 2024/5/21 上午 文章目录 多维数据库Cube的作用&#xff1a;什么是多维数据库维的级别多维数据分析方法如何构建多维数据集&#xff1f;创建项目创建数据源创建数据源视图创建多维数据集维度表中缺失的值拖拽过去建立维度结构设计类型启动连…...

win11安装docker运行Open-Webui 界面化展示 ollama大模型

1.OpenWeb UI运行需要docker 环境下载docker Get Started | Docker 2.需要命令提示符docker -v 查询是否安装成功&#xff1b; 查询docker详情docker version 3.github拉取open-webUi镜像Package open-webui GitHub 复制命令运行在命令提示符&#xff1b; 等待下载完成 4.到…...

网络模型-PoE技术

一、PoE简介 以太网供电PoE(Powerover Ethernet)是指通过以太网网络进行供电&#xff0c;也被称为基于局域网的供电系统PoL(PoweroverLAN)或有源以太网(Active Ethernet)。 1、PoE的优势: 可靠: 电源集中供电&#xff0c;备份方便。连接简捷: 网络终端不需外接电源&#xf…...

网站策划是什么

网站策划是指在建立、设计和运营一个网站时所采取的系统性规划和组织活动。它涵盖了从确定网站的目标和目标受众到确定内容、功能、设计和营销策略等方面的各个方面。在今天互联网时代的背景下&#xff0c;网站已经成为企业、组织和个人展示自身形象、提供信息和服务、开展交流…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...