小白都能看懂的力扣算法详解——链表(一)

!!本篇所选题目及解题思路均来自代码随想录 (programmercarl.com)

一 203.移除链表元素

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

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

我们的目标是要寻找val等于目标值的节点,那么我们就要遍历这个链表,找到该节点,之后让该节点的上一个节点指向它的下一个节点,即可实现“删除”。但是我们知道,单向链表只能指向它的下一个节点,那么我们该如何找到它的上一个节点呢?这里我能可以定义一个指针cur,让cur指向该元素的前一个节点,那么cur.next = cur.next.next 即实现了该节点的上一个节点指向它的下一个节点。因此我们可以得出cur.next = head;也就是说cur是头结点的前一个节点。解决了“删除”的问题,接下来思考如何实现寻找这个节点。也就是说,满足val等于目标值这个条件,翻译过来就是cur.next.val == targrt;(别忘了cur是当前节点的前一个节点,cur.next才是该节点)。也就是满足条件时执行cur.next = cur.next.next 操作,不满足条件时cur就移向下一个节点,继续遍历。最后一个问题,如何判断遍历何时结束?不难判断出,当cur指向链表的最后一个节点时,循环就该结束了(此时这个节点的val已经在cur指向它前一个节点时就对比过了),而cur.next为null也无法得到cur.next.val了。也就是说,我们的循环判断条件就是cur.next != null

整体思路结束,接下来来考虑一些特殊点,比如各种临界值。首先是当target==head.val的情况,满足cur.next.val == targrt条件;之后是target等于最后一个节点的值的情况,我们已经谈论过了;第三是链表长度为0的情况,此时head为null,即满足cur.next为null,退出循环;最后是有连续节点满足val等于target的情况,这时我们就会发现,如果有连续值满足条件,那么第二个节点就会被跳过对比,如何解决这个问题呢?我们可以在进行完cur.next = cur.next.next操作后,先不急着将cur向后移动(cur = cur.next),而是让它在原位置不动,这样下一轮比较cur.next.val时,cur.next就是第二个节点啦。

最后瞅一眼返回值,是返回头节点吗?如果直接返回head,那么如果head.val刚好等于target,已经被我们删除了,该怎么办?这时候就要请出我们的老朋友——虚拟头节点了(不熟也没关系,多刷几道链表题目之后就会发现,基本上有链表的地方就有它)。在最开始,设置一个虚拟头节点指向head,即p.next = head;无论头结点被删掉多少个,p.next都会指向它的下一项元素,也就是p始终都是“首个节点”,最后直接返回p.next即可。

class Solution {public ListNode removeElements(ListNode head, int val) {ListNode p = new ListNode();p.next = head;ListNode cur = p;while(cur.next != null) {if(cur.next.val == val) {cur.next = cur.next.next;} else {cur = cur.next;}}return p.next;}}

 代码随想录上提供了另一种不适用虚拟头节点的思路,这里直接附上代码,不再具体讲解。其实思路与上面几乎一致,只是多了一个对头节点是否需要删除的判断,就像上面说过的,如果head.val刚好等于target,已经被我们删除了,该如何找到链表的头部?

class Solution {public ListNode removeElements(ListNode head, int val) {while(head != null && head.val ==val) {head = head.next;}ListNode cru = head;while(cru != null && cru.next != null){if(cru.next.val == val) {cru.next = cru.next.next;} else{cru = cru.next;}}return head;}}

 关于此方法的具体讲解,以及该题目的视频讲解,其他语言版本代码,大家可以到代码随想录中自行查看。代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://www.programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

二 206.反转链表

题目描述:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

206. 反转链表 - 力扣(LeetCode)

 这道题乍一看很难(反正我是毫无思路),看到有一种暴力解法是将链表中的元素存储在数组中,反转数组,再放回到链表里,感觉可行但是我没具体尝试(也太暴力了一点......).听完卡尔哥的讲解之后我的感受只有两个字:秒啊。

回归正题,翻转链表我们很自然就能想到让下一个元素指向上一个元素,问题在于,在单向链表中,如何获得上一个元素的位置呢?这里又要用到虚拟头节点了。我们定义一个指针pre指向虚拟头节点,也就是head的前一个元素,再定义一个指针cur指向head,让cur.next指向pre,即可完成下一个元素指向上一个元素,之后我们只要向后移动pre和cur,循环上面的操作即可。是不是很完美?错!这种做法存在一个很明显的错误,当cur.next指向pre之后,head后面的节点就失去了指向它的头节点,如图,那么cur如何如我们所愿向后移动呢?

这时候,我们就需要清楚我们的第三个指针temp出场了。我们在执行cur.next = pre之前,先令p指向cur.next,如此一来,就可保留住cur下一个节点的位置,我们就能随意改变cur.next的指向了。当我们完成cur.next = pre的操作后,只要让cur = temp,就可以让cur指向它原先的下一个节点了。

大体思路完成,接下来思考实现细节。

1.什么时候终止循环?

当循环进行到这一步时,整个反转操作就完成了,再往下走(cur = null)也就没有了意义,所以可以得到,临界条件为cur!=null

2.返回值是什么?

搞不明白就画图,在最后一步操作执行完时,指针情况是这样的,此时cur!=null条件不满足,结束循环。原先的最后一个节点就是现在的头节点,也就是pre指针所指向的节点,因此我们返回pre。

3.链表为空或只有一个节点时,是否需要特殊讨论?

链表为空时,head也为空,此时自然满足cur=null的条件,不进入循环,返回pre,为空。符合。

链表只有头节点时,cur != null,完成第一轮交换,之后pre指向了head,cur执行null,退出循环,返回pre(head),满足。

class Solution {public ListNode reverseList(ListNode head) {ListNode cur = new ListNode();ListNode pre = new ListNode();cur = head;pre= null; while(cur != null ) {ListNode temp = new ListNode();temp = cur.next;cur.next = pre;pre = cur;cur = temp;}return pre;}
}

关于该题目的视频讲解,其他语言版本代码,大家可以到代码随想录中自行查看。

代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://www.programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html

三 707.设计链表

题目描述:

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

707. 设计链表 - 力扣(LeetCode)

 这道题非常非常非常麻烦,但是其实难度不是很高,建议大家可以做完其他链表题目后再翻回来做这道题,可能更容易一些。这里直接给出代码及相应注释,不再具体讲解,关于该题目的视频讲解以及其他语言版本代码,大家可以到代码随想录中自行查看。代码随想录 (programmercarl.com)icon-default.png?t=N7T8https://www.programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

 // 设计链表结构class ListNode {int val;ListNode next;ListNode(){}ListNode(int val) {this.val=val;}
}
// 初始化
class MyLinkedList {//size存储链表元素的个数int size;//虚拟头结点ListNode head;//初始化链表public MyLinkedList() {size = 0;head = new ListNode(0);}//获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点public int get(int index) {//如果index非法,返回-1if (index < 0 || index >= size) {return -1;}ListNode currentNode = head;//包含一个虚拟头节点,所以查找第 index+1 个节点for (int i = 0; i <= index; i++) {currentNode = currentNode.next;}return currentNode.val;}//在链表最前面插入一个节点,等价于在第0个元素前添加public void addAtHead(int val) {addAtIndex(0, val);}//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加public void addAtTail(int val) {addAtIndex(size, val);}// 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。// 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点// 如果 index 大于链表的长度,则返回空public void addAtIndex(int index, int val) {if (index > size) {return;}if (index < 0) {index = 0;}size++;//找到要插入节点的前驱ListNode pred = head;for (int i = 0; i < index; i++) {pred = pred.next;}ListNode toAdd = new ListNode(val);toAdd.next = pred.next;pred.next = toAdd;}//删除第index个节点public void deleteAtIndex(int index) {if (index < 0 || index >= size) {return;}size--;if (index == 0) {head = head.next;return;}ListNode pred = head;for (int i = 0; i < index ; i++) {pred = pred.next;}pred.next = pred.next.next;}
}

 

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

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

相关文章

数据库管理-第145期 最强Oracle监控EMCC深入使用-02(20240205)

数据库管理145期 2024-02-05 数据库管理-第145期 最强Oracle监控EMCC深入使用-02&#xff08;20240205&#xff09;1 监控方式2 度量配置3 阻塞4 DG监控总结 数据库管理-第145期 最强Oracle监控EMCC深入使用-02&#xff08;20240205&#xff09; 作者&#xff1a;胖头鱼的鱼缸&…

Java后端技术助力,党员学习平台更稳定

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Text Mesh Pro图文混排如何对任何图片都能实现

1&#xff09;Text Mesh Pro图文混排如何对任何图片都能实现 2&#xff09;Unity iOS平台的小图占用特别大的内存 3&#xff09;只在编辑器内&#xff0c;纹理不开启Read&Write情况下&#xff0c;如何获取纹理所有颜色值 4&#xff09;准备在海外发行游戏&#xff0c;有哪些…

07-Java桥接模式 ( Bridge Pattern )

Java桥接模式 摘要实现范例 桥接模式&#xff08;Bridge Pattern&#xff09;是用于把抽象化与实现化解耦&#xff0c;使得二者可以独立变化 桥接模式涉及到一个作为桥接的接口&#xff0c;使得实体类的功能独立于接口实现类&#xff0c;这两种类型的类可被结构化改变而互不影…

还是蓝海项目?浅谈steam海外道具搬运项目几个常见问题!

做steam这个项目做了已经3年多了。记得刚开始做的时候还是一个很冷门的项目&#xff0c;现在越来越多的朋友也开始了解这个项目。 其中不乏很多已经在别的地方了解过后来找我咨询的朋友。我发现一些同行或者说自媒体太过于虚假宣传&#xff0c;把steam这个项目说的太好了。也有…

Flink实战六_直播礼物统计

接上文&#xff1a;Flink实战五_状态机制 1、需求背景 现在网络直播平台非常火爆&#xff0c;在斗鱼这样的网络直播间&#xff0c;经常可以看到这样的总榜排名&#xff0c;体现了主播的人气值。 人气值计算规则&#xff1a;用户发送1条弹幕互动&#xff0c;赠送1个荧光棒免费…

海外云手机的核心优势

随着5G时代的到来&#xff0c;云计算产业正处于高速发展的时期&#xff0c;为海外云手机的问世创造了一个可信任的背景。在资源有限且需求不断增加的时代&#xff0c;将硬件设备集中在云端&#xff0c;降低个人用户的硬件消耗&#xff0c;同时提升性能&#xff0c;这一点单单就…

2024牛客寒假算法基础集训营1

A 找dfs这三个字符即可 #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std;typedef pair<int, int> PII; typedef long long ll;const int N 55;int n; char s[N];void solve() {cin >…

LeetCode Python - 1.两数之和

文章目录 题目答案运行结果 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能…

【网站项目】031网络游戏公司官方平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

博途PLC报警字FC(字寄存器按位访问)

博途PLC的字寄存器按位访问和拆分,请查看下面文章链接: https://rxxw-control.blog.csdn.net/article/details/121727057https://rxxw-control.blog.csdn.net/article/details/121727057西门子触摸屏报警都是以字为地址访问,所以离散报警信号我们需要将其组合为报警字输出,…

async 与 await(JavaScript)

目录捏 前言一、async二、await三、使用方法总结 前言 async / await 是 ES2017(ES8) 提出的基于 Promise 解决异步的最终方案。上一篇文章介绍了 回调地狱 与 Promise&#xff08;JavaScript&#xff09;&#xff0c;因为 Promise 的编程模型依然充斥着大量的 then 方法&#…

【芯片设计- RTL 数字逻辑设计入门 11.1 -- 状态机实现 移位运算与乘法 1】

文章目录 移位运算与乘法状态机简介SystemVerilog中的测试平台VCS 波形仿真 阻塞赋值和非阻塞赋值有限状态机&#xff08;FSM&#xff09;与无限状态机的区别 本篇文章接着上篇文章【芯片设计- RTL 数字逻辑设计入门 11 – 移位运算与乘法】 继续介绍&#xff0c;这里使用状态机…

MyBatis之动态代理实现增删改查以及MyBatis-config.xml中读取DB信息文件和SQL中JavaBean别名配置

MyBatis之环境搭建以及实现增删改查 前言实现步骤1. 编写MyBatis-config.xml配置文件2. 编写Mapper.xml文件&#xff08;增删改查SQL文&#xff09;3. 定义PeronMapper接口4. 编写测试类1. 执行步骤2. 代码实例3. 运行log 开发环境构造图总结 前言 上一篇文章&#xff0c;我们…

C++后端开发之Sylar学习二:配置VSCode远程连接Ubuntu开发

C后端开发之Sylar学习二&#xff1a;配置VSCode远程连接Ubuntu开发 没错&#xff0c;我不能像大佬那样直接在Ubuntu上面用Vim手搓代码&#xff0c;只能在本地配置一下VSCode远程连接Ubuntu进行开发咯&#xff01; 本篇主要是讲解了VSCode如何配置ssh连接Ubuntu&#xff0c;还有…

Oracle笔记-为表空间新增磁盘(ORA-01691)

如下报错&#xff1a; 原因是Oracle表空间满了&#xff0c;最好是新增一个存储盘。 #查XXX命名空间目前占用了多大的空间 select FILE_NAME,BYTES/1024/1024 from dba_data_files where tablespace_name XXXX #这里的FILE_NAME能查到DBF的存储位置#将对应的datafile设置为30g…

#免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程

Mac电脑苹果芯片读写NTFS硬盘bash脚本 &#xff08;ntfs.sh脚本内容在本文最后面&#xff09; ntfs.sh脚本可以将Mac系统(苹果M系芯片)上的NTFS硬盘改成可读写的挂载方式&#xff0c;从而可以直接往NTFS硬盘写入数据。此脚本免费&#xff0c;使用过程中无需下载任何收费软件。…

vue教程-介绍与使用

vue介绍 介绍 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。 安装 最简单的例子就是&#xff0c;创建一个htm…

云上未来:探索云计算的技术变革与应用趋势

一、云计算的起源和演进 1.1 早期计算模型 在探讨云计算的起源和演进之前&#xff0c;理解早期的计算模型对于构建全面的视角至关重要。早期计算模型的发展奠定了云计算的基础&#xff0c;为其演进提供了技术和理念的支撑。 1.1.1 集中式计算模型 在计算技术的早期阶段&…

JVM Java虚拟机入门指南

文章目录 为什么学习JVMJVM的执行流程JVM的组成部分类加载运行时数据区本地方法接口执行引擎 垃圾回收什么样的对象是垃圾呢内存溢出和内存泄漏定位垃圾的方法对象的finalization机制垃圾回收算法分代回收垃圾回收器 JVM调优参数JVM调优工具Java内存泄漏排查思路CPU飙高排查方案…