链表经典刷题--快慢指针与双指针
本篇总结链表解题思路----快慢指针,其实也就是双指针,这个快慢并不单纯指“快慢”,它更多的可以表示,速度快慢,距离长度,时间大小等等,用法很有趣也很独特,理解它的思想,是很有必要的。
- 🍭1.链表的中间结点----'速度'
- 🍭2.链表中倒数第k个结点----'距离'
- 🍭3.移除链表元素
🍭1.链表的中间结点----‘速度’
要求返回链表中的中间结点;
当有奇数个结点时,返回中间的结点,当有偶数个结点时,返回第二个中间结点。
传统的思想是遍历链表,算链表长度,然后再找中间值。
但如果只允许遍历一遍链表呢?这种方法就不好使了。
使用快慢指针,轻松解决。
什么叫快慢指针,就是让两个指针都指向链表同时往后走,一个指针每次走两步,称为快指针,一个指针每次走一步,称为慢指针。
当快指针走到尾时,而慢指针所指向的地方就是中间结点。
这种天才想法在后面的许多链表题中都有应用,对解题很棒。
本题需要注意一下奇数个和偶数个结点有什么不同,当结点为偶数时,fast走到了最后一个结点的后面,所以fast成为NULL,当结点为奇数时,fast走到最后一个结点停止,所以fast->next为NULL。所以这个循环的条件就是fast和fast->NULL都不为空时,快慢指针才能往后走。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* middleNode(struct ListNode* head)
{struct ListNode *fast,*slow;//设置两个指针fast=slow=head;//让快慢指针同时从开头走while(fast!=NULL&&fast->next!=NULL)//当fast不为NULL和fast->next不为空时,才可以正常走,一旦有一个为NULL,则说明两种情况中有一个完成。{slow=slow->next;//慢指针每次走一步fast=fast->next->next;//快指针每次走两步}return slow;//最后不管结点是偶数个还是奇数个,返回值都是慢指针指向的位置}
🍭2.链表中倒数第k个结点----‘距离’
先输入k,要求输出该链表的第k的位置上的结点。
传统思想,遍历链表,算出长度,然后用长度减k再加1即可。
那如果跟上面一样只给你遍历一遍链表那该怎么做呢?
同样方法,快慢指针
只不过这时比较的不是速度了,而是两个指针之间的距离。
我们可以让快指针先走k-1步,然后再让慢指针开始走,当快指针走到最后一个结点时停止,慢指针指向的就是要输出的。
我们还可以让快指针先走k步,然后让慢指针开始走,这时,快慢指针之间的距离就变成了k,当快指针走到最后一个结点时,慢指针其实指向的是前面的结点,而要让慢指针指向后面的结点,让快指针再走一步就可以了。
代码如下:
/*** struct ListNode {* int val;* struct ListNode *next;* };*//*** * @param pListHead ListNode类 * @param k int整型 * @return ListNode类*/
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {// write code herestruct ListNode *fast,*slow;//定义两个指针fast=slow=pListHead;//一开始快慢指针都指向开头if(fast==NULL)//如果链表为空链表则无法返回,返回NULLreturn NULL;int num=k-1;if(k==0)//如果是倒数0个那么也返回NULL{return NULL;}while(num--)//先让快指针走k-1步{if(fast->next==NULL)//我们要确保k的大小不能大于链表的长度对吧,当k的长度大于链表时,就会让链表访问越界,所以先给fast往后走时,要注意不能越界了,如果fast->next为NULL,则表明k是大于链表长度的,之间返回NULL{return NULL;}fast=fast->next;}while(fast->next)//判断结束的条件是当fast->next为NULL时,结束,也就是fast走到最后一个结点时停止,这时快慢指针之间的距离为k-1,而最好一个结点与慢指针所指向的结点的距离就是k-1{slow=slow->next;//慢指针和快指针一起走fast=fast->next;}return slow;//最后返回slow位置即可
}
第二种图解:
/*** struct ListNode {* int val;* struct ListNode *next;* };*//*** * @param pListHead ListNode类 * @param k int整型 * @return ListNode类*/
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {// write code herestruct ListNode *fast,*slow;//定义两个指针fast=slow=pListHead;if(fast==NULL)//当链表为空时,返回NULLreturn NULL;while(k--)//快指针先走k步{//要考虑k如果大于链表本身长度时就非法if(fast==NULL){return NULL;}fast=fast->next;//}while(fast)//这个和快指针先走k-1的结束条件不一样喔,这个结束条件应该是快指针走到最后结点的后面,所以是fast为NULL循环结束{slow=slow->next;//快慢指针一起走fast=fast->next;}return slow;//返回慢指针所在的位置
}
🍭3.移除链表元素
方法1:
我们可以按照传统单链表是如何删除来写。
单链表如何删除呢?
我们要删除这个结点,还要将前面的结点和后面的结点链接起来。这时我们就必须要记录下前面结点的地址了,不然单链表无法再找到前一个结点。
所以我们可以用双指针,一个是进行遍历的指针cur,另一个是用来记录它前面结点的位置的指针prev。
当cur->val!=val时,cur先赋值给prev记录这个位置,然后cur再往后走。
当cur->cal==val时,那么就要将前一个结点链接到后一个结点上。
pre->next=cur->next;
然后释放掉cur。
大体思路是这样,不过还有一些细节问题。
比如如果最后一个元素是要被删的,那么前面一个结点的next就变成野指针了。
所以我们需要将他置为NULL。
还有个问题,如果第一个就是要被删除的结点,那么prev->next就非法,所以要进行讨论
当prev= =NULL时,说明第一个结点就要被删除,相当于头删。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){struct ListNode*cur=head;//cur用来遍历链表,首先指向最前面的
struct ListNode*prev=NULL;//一开始prev为空
while(cur)//利用cur进行遍历
{if(cur->val!=val)//如果不等于{prev=cur;//让prev记录这个位置cur=cur->next;//cur往后走}else//如果等于{if(prev==NULL)//要考虑是否是第一个要删除的,当prev==NULL时,就是删除第一个结点{head=cur->next;//将头结点与第二个结点链接free(cur);//是否curcur=head;//cur往后走,也就是走到第二个结点位置}else{prev->next=cur->next;//将前面的与后面的链接free(cur);//删除中间的cur=prev->next;//cur往后走}}
}
return head;//返回头结点
}
方法2:
我们可以利用数组删除元素的思想来删除链表中的结点
在数组中我们是将不等于val的元素放入一个新的数组。
而在链表里我们也可以这样,当不等于val的结点我们就插入到一个新的链表上去,所以我们还需要创建一个新链表。
我们每次将新结点插入到新链表中时都需要找尾,非常烦人,我们可以定义一个尾指针tail,用来指向新插入结点的地址。
如果cur->val!=val那么就进行尾插,将新结点插入新链表
如果cur->val=val,那么cur 就往后走。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){struct ListNode*cur=head;
struct ListNode*tail=NULL,*newnode=NULL;//创建一个新结点
while(cur)//遍历链表
{if(cur->val!=val)//如果不相同,就把不相同的结点插入到新的链表中{//尾插if(newnode==NULL)//最初新链表肯定为空,可以直接将cur指向的不相同的结点放入到新链表中{newnode=tail=cur;}else{tail->next=cur;//cur所对应的结点插入到tail后面tail=tail->next;//tial要往后走,记录下一个插入结点的位置}cur=cur->next;//cur也要往后走}else{struct ListNode*next=cur->next;//如果元素相同,那先把这个结点的下一个结点地址记录下来free(cur);//释放这个要删除的结点cur=next;//cur往后走}
}if(tail!=NULL)//当tail不为空时,我们需要将tail的next置为NULLtail->next=NULL;
return newnode;
}
相关文章:

链表经典刷题--快慢指针与双指针
本篇总结链表解题思路----快慢指针,其实也就是双指针,这个快慢并不单纯指“快慢”,它更多的可以表示,速度快慢,距离长度,时间大小等等,用法很有趣也很独特,理解它的思想,…...
【Java集合框架】篇四:Set接口
1. Set及主要实现类特点 Set:无序、不可重复(去重)、存储value HashSet:底层使用HashMap,即使用 数组单项链表红黑树 结构进行存储。(jkd8中) LinkedHashSet:是HashSet的子类&…...

Python 数据库连接 + 创建库表+ 插入【内含代码实例】
人生苦短 我用python Python其他实用资料:点击此处跳转文末名片获取 数据库连接 连接数据库前,请先确认以下事项: 您已经创建了数据库 TESTDB.在TESTDB数据库中您已经创建了表 EMPLOYEEEMPLOYEE表字段为 FIRST_NAME, LAST_NAME, AGE, SEX 和 INCOME。连…...

DSS 部署环境需求清单
文章目录 DSS系统需求项目地址计算资源计算基准:计算引擎程序硬件需求表 :DSS计算及存储资源需求计算资源计算基准:计算程序硬件需求表:DSS系统需求 项目地址 https://github.com/WeBankFinTech/DataSphereStudio 计算资源计算基准: 1.日活用户10万。 2.单用户单日总…...

Python的面向对象,详细讲解Python之用处等基本常识
目录 Python 面向对象 面向对象技术简介 创建类 实例 实例 self代表类的实例,而非类 实例 创建实例对象 访问属性 实例 Python内置类属性 实例 python对象销毁(垃圾回收) 实例 实例 类的继承 实例 方法重写 实例 基础重载方法 运算符重载 实例…...

如何使用固态继电器为恒温器供电
恒温器有两种电源:电池和 24VAC。恒温器需要电池才能不间断地运行。电池消耗的能量尽可能低非常重要,但即使您最大限度地减少消耗,这仍然不是一个用户友好的选择,因为电池会不时需要更换。要降低更换频率,可以使用 24V…...

【LeetCode】剑指 Offer(14)
目录 题目:剑指 Offer 32 - I. 从上到下打印二叉树 - 力扣(Leetcode) 题目的接口: 解题思路: 代码: 过啦!!! 写在最后: 题目:剑指 Offer 32…...

Rman单实例迁移到单实例
关于同平台同版本数据库之间的迁移操作的实验 ---Source DB[rootoracle-db-19cs ~]# cat /etc/redhat-release CentOS Stream release 8 [rootoracle-db-19cs ~]# --- Target DB[rootoracle-db-19ct ~]# cat /etc/redhat-release CentOS Stream release 8 [rootoracle-db-19ct…...

毕业设计 基于stm32舞台彩灯控制器设计app控制系统
基于stm32舞台彩灯控制器设计app控制1、项目简介1.1 系统构成1.2 系统功能2、部分电路设计2.1 STM32F103C8T6核心系统电路设计2.2 WS2812RGB彩灯电路设计3、部分代码展示3.1 控制WS2812显示颜色3.2 设置RGB灯的颜色,角度,亮度实物图1、项目简介 选题指导…...

【MyBatis】篇一.
文章目录1、MyBatis概述2、环境搭建1、MyBatis概述 认识: JavaEE开发的一个套件SSM,即: MyBatis是一个持久层的框架,是对JDBC的一个封装,是一个半自动的ORM框架。 ORM即实体类对象和数据库中的数据的一个映射关系&am…...

【JavaScript速成之路】JavaScript流程控制
📃个人主页:「小杨」的csdn博客 🔥系列专栏:【JavaScript速成之路】 🐳希望大家多多支持🥰一起进步呀! 文章目录前言1,流程控制2,分支结构2.1,if语句2.2&…...
18、基准测试,sysbench
基准测试,sysbench 1. sysbench1.1 用途1.2 安装1.3 版本1.4 查看帮助1.5 测试过程阶段2 CPU 性能测试2.1 测试原理2.2 查看帮助2.3 测试3. 内存性能测试3.1 查看帮助信息3.2 测试过程4.磁盘性能基准测试4.1 查看帮助4.2 生成文件(prepare)4.3 测试文件io(run)4.4 结果分析4.5…...
3D,点云拼接2
文章目录 点云配准方法自动配准技术PCL实现的配准算法两两配准1.关键点提取2.特征描述符3. 对应关系估计4. 对应关系去除5. 变换矩阵估算在上篇文章中对于拼接的概念、拼接精度的评价做了详细的介绍。本文是对拼接(配准)的进一步介绍,涉及更多原理层面的东西。 主要围绕以下三…...
jmeter学习笔记一(http基础知识)
HTTP请求:客户端同通过发送http请求向服务器请求资源的访问。http请求由三部分组成:请求行、请求头、请求正文 请求行包括:请求方法 URI 协议/版本 请求头:Content-type、Cookie、Authorization、User-Agent、Accept、Acc…...

【Java】CompletableFuture 并发顺序调度
前言 Java CompletableFuture 提供了一种异步编程的方式,可以在一个线程中执行长时间的任务,而不会堵塞主线程。 和Future相比,CompletableFuture不仅实现了Future接口,也实现了 CompletionStage接口。Future接口不用多说&#…...

职场人必备的6款实用办公app,每一款都是心头爱
打工人不容易啊,不提高工作效率怕是要被淘汰了。今天给大家分享6款职场人必备的实用办公APP,免费效率神器让工作事半功倍。这些APP每一款都是我的心头爱,肯定会让人大开眼界的,超级实用,直接往下看吧。1、向日葵远程控…...
小丑改造计划之复习一
1.函数重载 根据参数个数 参数顺序 参数类型 的不同 可以在同一个域存在多个同名函数 但是不可以根据返回值 缺省参数的不同去重载函数 2.指针和引用的区别 第一点 指针是内存地址,会开辟内存空间,而引用和它所引用的变量共享同一块内存 第二点 引用必须…...

final修饰符使用中遇到的一些问题
文章目录final修饰符1. final不能用来修饰构造方法2. final修饰变量的一些注意问题2.1 final修饰成员变量2.2 final修饰引用类型2.2.1 演示代码中lombok链式编程介绍final修饰符 final具有“不可改变”的含义,它可以修饰非抽象类、非抽象成员方法和变量。 用final…...

好记又实用的获取电脑型号方法
个人常用的方法 方法二最好记又好用。 方法一 dxdiag命令 按下键盘WINR调出运行在输入框输入dxdiag命令后,按下回车;进入DirectX诊断工具,便可查看系统型号等信息。 这里就会显示系统型号。 方法二 设备和打印机 控制面板-查看方式-小图…...
@Transactional配置详解
一:事务注解Transactional,属性propagation的7个配置 PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。,默认配置,也是常用的选择。 PROPAGATION_SUPPORTS -- 支持当前事务&#…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...