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

算法 day4 【双指针、快慢指针、环形链表】链表下

⚡刷题计划day4继续,可以点个免费的赞哦~

下一期将会开启哈希表刷题专题,往期可看专栏,关注不迷路,

您的支持是我的最大动力🌹~

目录

⚡刷题计划day4继续,可以点个免费的赞哦~

下一期将会开启哈希表刷题专题,往期可看专栏,关注不迷路,

您的支持是我的最大动力🌹~

题目一:19. 删除链表的倒数第 N 个结点

法一:计算链表长度

法二:双指针

题目二:面试题 02.07. 链表相交

法一:双指针

法二:合并链表实现同步移动

题目三:142. 环形链表 II

法一:快慢指针法

1.判断链表是否有环

2.如果有环,如何找到环的入口

2.1 n==1

2.2 n>1

法二:哈希表


题目一:19. 删除链表的倒数第 N 个结点

leetcode:19. 删除链表的倒数第 N 个结点

(https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/)

法一:计算链表长度

常规思路:先遍历得到链表长度L,然后再次遍历到 L-n+1个结点,便是我们需要删除的结点;

这里我们还是使用虚拟头结点统一,于是从虚拟结点开始遍历L-n+1个结点,它的下一个结点便是我们要删除的结点,这样我们只需修改一次指针,就可完成删除操作。

如图辅助理解:

AC代码

class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummyHead = new ListNode();dummyHead.next=head;ListNode cur = dummyHead;int length = getLength(head);for (int i=1;i<length-n+1;i++){cur = cur.next;}if(cur.next!=null){//避免空指针cur.next = cur.next.next;//删除操作}return dummyHead.next;
​}public int getLength(ListNode head){int length = 0;while(head != null){length++;head=head.next;}return length;}
}

法二:双指针

主要思路:

要删除倒数第n个,我们可以使用双指针,这样不用去求长度;

保持一个相差n的区间,fast在前,slow在后。这样等fast走到链表末尾,slow对应的就是我们要删除的结点;

因为链表删除我们需要通过前一个结点,所以将相差区间设为n+1,可以结合图理解:

AC代码

class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummyHead = new ListNode();dummyHead.next=head;ListNode fast = dummyHead;ListNode slow = dummyHead;
​// 只要快慢指针相差 n 个结点即可for (int i=1;i<=n+1;i++){fast = fast.next;}while (fast!=null){fast = fast.next;slow = slow.next;}
​if(slow.next!=null){slow.next = slow.next.next;}return dummyHead.next;}
}

题目二:面试题 02.07. 链表相交

leetcode:面试题 02.07. 链表相交

(https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/)

简单来说,就是求两个链表交点节点的指针。 这里要注意,交点不是数值相等,而是指针相等。

为了方便举例,假设节点元素数值相等,则节点指针相等。

看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:

我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图

此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。

否则循环退出返回空指针。

AC代码

法一:双指针

public class Solution {
​public ListNode getIntersectionNode(ListNode headA, ListNode headB) {// 初始化两个链表的当前节点ListNode cur1 = headA;ListNode cur2 = headB;// 初始化两个链表的长度int len1 = 0;int len2 = 0;
​// 求cur1长度while (cur1 != null) {len1++;cur1 = cur1.next;}// 求cur2长度while (cur2 != null) {len2++;cur2 = cur2.next;}
​// 重新初始化两个链表的当前节点cur1 = headA;cur2 = headB;
​// 如果第一个链表比第二个短,交换两个链表的头节点和长度if (len1 < len2) {//1. swap (len1, len2);int temp = len1;len1 = len2;len2 = temp;//2. swap (cur1, cur2);ListNode temNode = cur1;cur1 = cur2;cur2 = temNode;}
​// 计算长度的差值int gap = len1 - len2;// 移动较长链表的当前节点,使cur1与cur2的末尾位置对齐,看图while (gap-- > 0) {cur1 = cur1.next;}
​// 同时遍历两个链表,遇到相同则直接返回while (cur1 != null) {if (cur1 == cur2) {return cur1; // 返回相交的节点}cur1 = cur1.next;cur2 = cur2.next;}
​// 如果两个链表没有相交,返回nullreturn null;}
}

法二:合并链表实现同步移动

主要思路:

  1. 同步移动指针

    • 使用一个 while 循环,只要 p1p2 没有相遇,就继续移动指针。

    • 对于 p1,如果它到达了链表 A 的末尾(即 p1null),则将它移动到链表 B 的头部,重新开始遍历。

    • 对于 p2,如果它到达了链表 B 的末尾(即 p2null),则将它移动到链表 A 的头部,重新开始遍历。

  2. 相遇即相交

    • 当两个指针 p1p2 相遇时,它们指向的就是链表相交的节点。因为两个指针最终都会遍历完两个链表,如果链表有相交点,它们最终会在相交点相遇。

  3. 返回结果

    • 一旦 p1p2 相遇,即它们指向同一个节点,就返回这个节点。

 public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {// p1 指向 A 链表头结点,p2 指向 B 链表头结点ListNode p1 = headA, p2 = headB;while (p1 != p2) {// p1 走一步,如果走到 A 链表末尾,转到 B 链表if (p1 == null) p1 = headB;else            p1 = p1.next;// p2 走一步,如果走到 B 链表末尾,转到 A 链表if (p2 == null) p2 = headA;else            p2 = p2.next;}return p1;}
}

题目三:142. 环形链表 II

leetcode:142. 环形链表 II

(https://leetcode.cn/problems/linked-list-cycle-ii/description/)

法一:快慢指针法

判断链表是否有环,我们一般可以使用快慢指针法

此题还是有一定难度,考察了对链表环的判断,已经需要进行数学运算,下文会进行详细解释。

对于此题大致分为两大步:

1.判断链表是否有环

2.如果有环,如何找到环的入口


1.判断链表是否有环

分别定义fast,slow指针,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

2.如果有环,如何找到环的入口

这步已经可以判断链表是否有环了,接下来是寻找环的入口,需要用到一点数学运算。

假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。 如图所示:

那么当相遇时:

slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。

加深理解注:

1.fast指针为什么 n (y + z)? 因为fast比slow快,fast进入圈后至少需要一圈后追反超slow,由此也可知道,n>=1(后续解题会用)。

2.为什么slow就不用比如k(y+z)? 因为slow进入圈后在一圈内一定会被fast追上

3.那为什么slow一圈内就一定会被fast追上呢? 可以这样通俗理解:首先fast会比slow快1,如果slow走一圈,fast就会走两圈,那一定会追上。

因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 slow指针走过的节点数 * 2 = fast指针走过的节点数,所以可以列出方程:

(x + y) * 2 = x + y + n (y + z)

因为我们要找环形入口,即需要找x,将x单独放出来化简:

x = n (y + z) - y

但是我们看一下这个式子呢,也发现不了什么,我们是想通过右边的参数来求x,但发现目前右侧也没啥特殊形式,还有个-y。于是我们可以提一个(y+z)出来,

x = (n - 1) (y + z) + z(此处n>=1,前面有解释)

此时就明了了。


2.1 n==1

当 n为1的时候,公式就化解为 x = z

这就意味着,从头结点出发一个指针,从相遇节点也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点

也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。

让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。

2.2 n>1

那么 n如果大于1是什么情况呢,就是fast指针在环形转n圈之后才遇到 slow指针。

其实这种情况和n为1的时候效果是一样的,一样可以通过这个方法找到 环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。

代码如下:

public class Solution {public ListNode detectCycle(ListNode head) {ListNode fast = head;ListNode slow = head;while(fast!=null && fast.next!=null){fast = fast.next.next;slow = slow.next;
​//相遇,有环if(fast==slow){ListNode index1  = fast;ListNode index2  = head;// 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口while (index1 != index2){index1 = index1.next;index2 = index2.next;}return index1;}
​}return null;}
}

法二:哈希表

这个思路就简单很多,时间复杂度:O(N),空间复杂度:O(N);

但第一种双指针的解法也需要掌握,时间复杂度:O(N),空间复杂度:O(1)。

关于哈希表我们下期也会做相应的专题刷题。

主要思路:遍历链表中的每个节点,并将它记录下来;一旦遇到了此前遍历过的节点,就可以判定链表中存在环。借助哈希表可以很方便地实现。

代码:

详细见注解

public class Solution {public ListNode detectCycle(ListNode head) {// 初始化指针pos指向头结点ListNode pos = head;// 使用HashSet来存储已经访问过的节点Set<ListNode> visited = new HashSet<ListNode>();
​// 遍历链表while (pos != null) {// 如果当前节点已经被访问过,说明存在环,返回当前节点if (visited.contains(pos)) {return pos;} else {// 否则,将当前节点添加到visited集合中visited.add(pos);}// 移动到下一个节点pos = pos.next;}
​// 如果遍历完整个链表都没有发现环,返回nullreturn null;}
}

相关文章:

算法 day4 【双指针、快慢指针、环形链表】链表下

⚡刷题计划day4继续&#xff0c;可以点个免费的赞哦~ 下一期将会开启哈希表刷题专题&#xff0c;往期可看专栏&#xff0c;关注不迷路&#xff0c; 您的支持是我的最大动力&#x1f339;~ 目录 ⚡刷题计划day4继续&#xff0c;可以点个免费的赞哦~ 下一期将会开启哈希表刷题…...

智能音箱的工作原理

智能音箱的工作原理主要涉及到硬件和软件两个层面的协同工作&#xff0c;以及多个关键技术环节的配合。以下是对智能音箱工作原理的详细解析&#xff1a; 一、硬件层面 智能音箱的硬件组成通常包括主控芯片、麦克风阵列、扬声器、Wi-Fi模块和电源等部分。 主控芯片&#xff1…...

国际金融入门:国际收支与平衡表解析

在全球化的经济体系中&#xff0c;国际金融已成为我们日常生活不可或缺的一部分。了解国际金融的基础知识&#xff0c;可以帮助我们更好地理解世界经济的动态和趋势。今天&#xff0c;我们将深入探讨国际收支及其平衡表&#xff0c;以及它们是如何影响国家经济。 国际收支&…...

Modbus转BACnet/IP网关的技术实现与应用

引言 随着智能建筑和工业自动化的快速发展&#xff0c;不同通信协议之间的数据交换也变得日益重要。Modbus和BACnet/IP是两种广泛应用于自动化领域的通信协议&#xff0c;Modbus以其简单性和灵活性被广泛用于工业自动化&#xff0c;而BACnet/IP则在楼宇自动化系统中占据主导地…...

数据库连接断开后,DBAPI的数据源如何自动重连

现象 在使用DBAPI的过程中&#xff0c;如果网络抖动导致数据库连接不上&#xff0c;发现DBAPI的数据源不能重连&#xff0c;必须重启DBAPI才能连上数据库 解决办法 在数据源的连接池参数配置druid.breakAfterAcquireFailurefalse注意在企业版的4.1.1及以上版本才可以配置连接…...

Microsoft 365 Office BusinessPro LTSC 2024 for Mac( 微软Office办公套件)

Microsoft 365 Office BusinessPro LTSC 2024是一款专为商业用户设计的办公软件套件&#xff0c;它集成了Word、Excel、PowerPoint等核心应用&#xff0c;并特别包含了Microsoft Teams这一强大的协作工具。Teams将聊天、会议、文件共享、任务管理等功能整合到一个平台上&#x…...

svelte - 1. 基础知识

svelte中文官网 vue和svelt语法对比 掘金-svelte入门简介 文章目录 1、基本页面框架2、动态属性3、嵌套组件4、@html: 插入html标签,显示真实dom元素5、点击事件 on:click={handleClick}6、响应式声明7、父子组件通信8、if-else(1)if(2)if - else(3)if - else if - else…...

挖掘基于边缘无线协同感知的低功耗物联网 (LPIOT) 的巨大潜力

关键词&#xff1a;边缘无线协同感知、低功耗物联网(LPIOT)、无线混合组网、用电监测、用电计量、多角色、计量插座、无线场景感知、多角色运用、后台边缘层&#xff0c;网络边缘层&#xff0c;场景能效管理&#xff0c;场景能耗计算 在数字化和智能化日益加速的今天&#xff…...

iOS开发设计模式篇第一篇MVC设计模式

目录 1. 引言 2.概念 1.Model 1.职责 2.实现 3.和Controller通信 1.Contrller直接访问Model 2.通过委托(Delegate)模式 3.通知 4.KVO 4.设计的建议 2.View 1.职责 2.实现 3.和Controller通信 1. 目标-动作&#xff08;Target-Action&#xff09;模式 2…...

【React】全面解析:从基础知识到高级应用,掌握现代Web开发利器

文章目录 一、React 的基础知识1. 什么是 React&#xff1f;2. React 的基本概念3. 基本示例 二、React 的进阶概念1. 状态&#xff08;State&#xff09;和属性&#xff08;Props&#xff09;2. 生命周期方法&#xff08;Lifecycle Methods&#xff09;3. 钩子&#xff08;Hoo…...

神经网络之卷积神经网络

目录 一、卷积神经网络概述&#xff1a;1.卷积层&#xff1a;1.1卷积核与神经元&#xff1a;1.2卷积层作用&#xff1a;1.3多输出通道概念&#xff1a; 2.池化层&#xff1a;2.1池化层作用&#xff1a; 3.隐藏层与卷积层、池化层关系&#xff1a; 一、卷积神经网络概述&#xf…...

【Vue实战教程】之Vue工程化项目详解

Vue工程化项目 随着多年的发展&#xff0c;前端越来越模块化、组件化、工程化&#xff0c;这是前端发展的大趋势。webpack是目前用于构建前端工程化项目的主流工具之一&#xff0c;也正变得越来越重要。本章节我们来详细讲解一下如何使用webpack搭建Vue工程化项目。 1 使用we…...

DBeaver Ultimate 22.1.0 连接数据库(MySQL+Mongo+Clickhouse)

前言 继续书接上文 Docker Compose V2 安装常用数据库MySQLMongo&#xff0c;部署安装好之后我本来是找了一个web端的在线连接数据库的工具&#xff0c;但是使用过程中并不丝滑&#xff0c;最终还是选择了使用 DBeaver &#xff0c;然后发现 mongo 还需要许可&#xff0c;又折…...

探索PyMuPDF:Python中的强大PDF处理库

探索PyMuPDF&#xff1a;Python中的强大PDF处理库 背景&#xff1a;为何选择PyMuPDF 在数字化时代&#xff0c;PDF文件因其跨平台的兼容性和对格式的严格保持而成为文档交换的通用格式。然而&#xff0c;处理PDF文件往往需要专门的工具或库。这就是PyMuPDF库的用武之地。PyMuP…...

天润融通AI技术助力汽车行业销售革新,邀约到店率翻倍增长

2024年汽车行业增速放缓&#xff0c;市场竞争加剧。在这种背景下&#xff0c;人工智能的加速渗透&#xff0c;各大汽车厂商纷纷引入大模型技术&#xff0c;对传统营销方式进行升级改造&#xff0c;寻找新的增长空间。 一直以来&#xff0c;汽车厂商投入大量预算&#xff0c;对…...

ubuntu安装mysql8.0

文章目录 ubuntu版本安装修改密码取消root跳过密码验证 ubuntu版本 22.04 安装 更新软件包列表 sudo apt update安装 MySQL 8.0 服务器 sudo apt install mysql-server在安装过程中&#xff0c;系统可能会提示您设置 root 用户的密码&#xff0c;请务必牢记您设置的密码。…...

数字图像处理笔记(三) ---- 傅里叶变换的基本原理

系列文章目录 数字图像处理笔记&#xff08;一&#xff09;---- 图像数字化与显示 数字图像处理笔记&#xff08;二&#xff09;---- 像素加图像统计特征 数字图像处理笔记&#xff08;三) ---- 傅里叶变换的基本原理 文章目录 系列文章目录前言一、傅里叶变换二、离散傅里叶变…...

Golang | Leetcode Golang题解之第268题丢失的数字

题目&#xff1a; 题解&#xff1a; func missingNumber(nums []int) int {n : len(nums)total : n * (n 1) / 2arrSum : 0for _, num : range nums {arrSum num}return total - arrSum }...

Xlua原理 二

一已经介绍了初步的lua与C#通信的原理&#xff0c;和xlua的LuaEnv的初始化内容。 这边介绍下Wrap文件。 一.Wrap介绍 导入xlua后可以看到会多出上图菜单。 点击后生成一堆wrap文件&#xff0c;这些文件是lua调用C#时进行映射查找用的中间代码。这样就不需要去反射调用节约性…...

《数据结构》--顺序表

C语言语法基础到数据结构与算法&#xff0c;前面已经掌握并具备了扎实的C语言基础&#xff0c;为什么要学习数据结构课程&#xff1f;--我们学完本章就可以实践一个&#xff1a;通讯录项目 简单了解过后&#xff0c;通讯录具备增加、删除、修改、查找联系人等操作。要想实现通…...

Qt:愚蠢的qmake

博主参与了一个使用qmake构建的项目&#xff0c;包含几百个源文件&#xff0c;最近遇到一个恼人的问题&#xff1a;有时仅仅修改了一个.cpp文件&#xff0c;构建项目时就有可能触发全编译。但是编译时又会命中ccache的缓存&#xff0c;这说明源代码实际上内容并没有发生变化。即…...

Apache Dubbo:分布式服务框架的深度解析

文章目录 引言官网链接Dubbo 原理架构概览通信协议负载均衡 基础使用1. 引入依赖2. 配置服务提供者3. 配置服务消费者4. 配置注册中心 高级使用1. 集群容错2. 泛化引用3. 异步调用 优缺点优点缺点 结论 引言 Apache Dubbo 是一个高性能、轻量级的开源 Java RPC 框架。它提供了…...

【前端学习】CSS三大特性

CSS三大特性 CSS的三大特性是为了化简代码、定位问题并且解决问题 继承性 继承性特点&#xff1a; 子级默认继承父级的文字控制属性。注意&#xff1a;如果标签自己有样式则生效自己的样式&#xff0c;不继承。 <!DOCTYPE html> <html lang"en"><…...

了解网络是如何运作

“Web 的工作原理”提供了一个简化的视图,用于了解在计算机或手机上的 Web 浏览器中查看网页时发生的情况。 这个理论对于短期内编写 Web 代码来说并不是必需的,但不久之后,你就会真正开始从理解后台发生的事情中受益。 客户端和服务器 连接到 Internet 的计算机称为客户端和…...

传输层协议——TCP

TCP协议 TCP全称为“传输控制协议”&#xff0c;要对数据的传输进行一个详细的控制。 特点 面向连接的可靠性字节流 TCP的协议段格式 源/目的端口&#xff1a;表示数据从哪个进程来&#xff0c;到哪个进程4位首部长度&#xff1a;表示该TCP头部有多少字节&#xff08;注意它…...

C++相关概念和易错语法(23)(set、仿函数的应用、pair、multiset)

1.set和map存在的意义 &#xff08;1&#xff09;set和map的底层都是二叉搜索树&#xff0c;可以达到快速排序&#xff08;当我们按照迭代器的顺序来遍历set和map&#xff0c;其实是按照中序来遍历的&#xff0c;是排过序的&#xff09;、去重、搜索的目的。 &#xff08;2&a…...

netty入门-3 EventLoop和EventLoopGroup,简单的服务器实现

文章目录 EventLoop和EventLoopGroup服务器与客户端基本使用增加非NIO工人NioEventLoop 处理普通任务与定时任务 结语 EventLoop和EventLoopGroup 二者大概是什么这里不再赘述&#xff0c;前一篇已简述过。 不理解也没关系。 下面会简单使用&#xff0c;看了就能明白是什么 这…...

通信原理-思科实验五:家庭终端以太网接入Internet实验

实验五 家庭终端以太网接入Internet实验 一实验内容 二实验目的 三实验原理 四实验步骤 1.按照上图选择对应的设备&#xff0c;并连接起来 为路由器R0两个端口配置IP 为路由器R1端口配置IP 为路由器设备增加RIP&#xff0c;配置接入互联网的IP的动态路由项 5.为路由器R1配置静…...

【Vue】vue概述

1、简介 Vue.js&#xff08;简称Vue&#xff09;是一款用于构建用户界面的渐进式JavaScript框架。由前Google高级软件工程师尤雨溪&#xff08;Evan You&#xff09;于2014年创建&#xff0c;是一个独立且社区驱动的开源项目。Vue.js基于标准的HTML、CSS和JavaScript&#xff…...

Docker use experience

#docker command docker load -i <镜像文件.tar> docker run -it -d --name 容器名 -p 宿主机端口:容器端口 -v 宿主机文件存储位置:容器内文位置 镜像名:Tag /bin/bash docker commit -m"提交的描述信息" -a"作者" 容器ID 要…...