LeetCode-141环形链表 LeetCode-142环形链表二

一、前言

本篇文章在我之前讲完的链表、链表与递归的基础上进行讲解,本次我们以leetcode为例,讲解链表的其他题型,今天我们先了解一下环形链表,这里我们以leetCode141和leetCode142为例。

二、LeetCode141

在这里插入图片描述
首先关于这道题,我们知道链表有着天然的递归性质,我们可以借助哈希表,如果链表有环,那么当通过环走到相同节点的时候,在哈希表一定能找到。所以对于递归求解,最基本的问题就是分为有环和无环,如果无环,那么当当前节点等于NULL,直接return false即可。如果有环,那么当hashSet找到此节点时,直接return true即可。然后把head.next作为参数调用递归函数即可。
代码如下:

public static boolean hasCycle(ListNode head) {if (head == null || head.next == null) {return false;}HashSet<ListNode> hashSet = new HashSet<>();return hasCycleRecursion(hashSet,head);}private static boolean hasCycleRecursion(HashSet<ListNode> hashSet, ListNode head) {if(head == null){return false;}if(hashSet.contains(head)){return true;}hashSet.add(head);return hasCycleRecursion(hashSet,head.next);}

在这里插入图片描述
那么这道题有没有更优解呢,答案是有的,这里我们就要介绍一种特殊的算法:快慢指针。
快慢指针的原理,就是让快慢指针同时从head出发,快指针一次走两格,而慢指针一次走一格。
如果链表无环,那么快指针肯定会走到NULL,从而快慢不可能相遇。如果链表有环,快慢指针都会陷入环中进行无限次移动,然后变成了追及问题。想象一下在操场跑步的场景,只要一直跑下去,快的总会追上慢的。因为它们的相差速度就是一,当两个指针都进入环后,每轮移动使得慢指针到快指针的距离增加一,同时快指针到慢指针的距离也减少一,只要一直移动下去,快指针总会追上慢指针。还不懂的话,我们以相对速度的角度去看,此时slow不动,fast每次以一的速度去追slow,那么这样肯定是能追上slow的。
在这里插入图片描述
那么这样就很简单了,我们定义slow和fast都从head出发,只要fast.next和fast.next.next均不为空,那么就让slow和fast开始移动,如果在移动过程中slow==fast,那么就说明有环,否则无环:

  public static boolean hasCycle(ListNode head) {if(head == null){return false;}ListNode slow = head;ListNode fast = head;while (fast.next != null && fast.next.next != null){slow = slow.next;fast = fast.next.next;if(fast == slow){return true;}}return false;}

在这里插入图片描述
有些人可能会问,快慢指针为什么快指针一定要是慢指针的两倍,我不可以是三倍吗
其实三倍也可以,只是反而可能拖累效率,推导如下
在这里插入图片描述
如上图,非环长s,环长t,环入口距离相遇点j,假设快指针比慢指针速度快k倍,当两者相遇,此时慢指针走了s+j,快指针走了
s+j+n*t(n为快指针在环中的圈数)。
那么有s+j+n*t=k(s+j),推导一下有(n*t)/(k-1)=s+j,也可以写为(n/k-1)*t = s+j
我们知道这个式子的参数一定都是整数,那么k-1也一定要是正整数,在其他量都确定的情况下,保持(n / k-1)不变的话,分母k-1越小,则分子n也越小,对应快指针在环中走的圈数n也越小,k=2,3,4···,其中k=2时,m最小,即最快相遇,这样效率最高。如果k=3,反而可能影响效率。
故我们快指针设定一次走两步。

三、LeetCode142

那么如果我们需要找到环入口该如何去做呢,拿LeetCode142为例:
在这里插入图片描述
做法一,其实上面的哈希表大家仔细想想,已经做完了这道题,当我发现哈希表重复的节点的时候,那个重复的节点就是环入口。
所以把141的代码稍微改下返回值就可以提交了:

public ListNode detectCycle(ListNode head) {if(head == null || head.next == null){return null;}HashSet<ListNode> listNodes = new HashSet<>();return detectCycleRecursion(listNodes,head);}private ListNode detectCycleRecursion(HashSet<ListNode> listNodes, ListNode head) {if(head == null){return null;}if(listNodes.contains(head)){return head;}listNodes.add(head);return detectCycleRecursion(listNodes,head.next);}

在这里插入图片描述
那么解法二自然还是之前的快慢指针了,我们首先定义快慢指针,然后沿用判环的代码,如果快慢指针相遇,说明有环,此时在这个基础上,我们来推导环的入口:
在这里插入图片描述
设a为head到环入口的距离,环长为t
此时快指针比慢指针多走nt步(因为slow和fast都走了a步),设立f为fast走的,s为slow走的,有f=2s,f=s+nt
由上面的结论可以得到s=nt,即慢指针走了nt距离
假设从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nt
那么根据上面s=nt,头节点走到环入口是a+nt,我们只需要让慢指针再走a步即可达到环入口而头节点距离环入口刚好是a。那么就是头节点和慢指针一起出发,相遇的节点就是环入口
所以当快慢指针相遇的时候,我们定义两个指针,分别从head和slow出发,一次走一步,相遇点就是环入口,代码如下:

	public static ListNode detectCycle(ListNode head) {if(head == null){return null;}ListNode slow = head;ListNode fast = head;while (fast.next != null && fast.next.next != null){slow = slow.next;fast = fast.next.next.next;if(slow == fast){ListNode newSlow = slow;ListNode newHead = head;while (newSlow != newHead){newSlow = newSlow.next;newHead = newHead.next;}return newHead;}}return null;}

在这里插入图片描述
这里最后提一嘴,如果要求环长,首先当然还是可以用hash表,和上面思路一样,当发现一样的元素时,此时看哈希表的长度即可。
而另一种方法就是当快慢指针相遇时,由于此时肯定是有环的,我只需要让慢指针一格一格往前走,快指针不动,当慢指针再次和快指针相遇时,此时慢指针走的距离就是环长。这里代码就不做赘述,比较简单,大家可以自行实现。

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

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

相关文章

微服务注册中心之Eureka

微服务注册中心之Eureka eureka 搭建集群 版本说明 Spring Boot 2.1.7.RELEASE spring-cloud-starter-netflix-eureka-server Finchley.SR2 spring-boot-starter-security 2.1.7.RELEASE pom.xml 文件 <?xml version"1.0" encoding"UTF-8"?> &l…

游戏缺少emp.dll详细修复教程,快速解决游戏无法启动问题

在现代游戏中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“emp.dll丢失”。emp.dll是一个动态链接库文件&#xff0c;它包含了许多程序运行所需的函数和数据。当一个程序需要调用这些函数时&#xff0c;系统会从emp.dll文件中加载相应的内容。因此&#x…

VSCode上远程调试代码出现的问题

记录一下&#xff1a; 真的是汗流浃背了&#xff0c;师妹叫帮忙如何在VSCode上远程调试代码&#xff0c;一些自己已经经历过的问题&#xff0c;现在已经忘记了。又在网上一顿搜索&#xff0c;这次记录下吧。。。 出现以下问题&#xff1a; 1. 终端界面总是sh-4.4 $ &#xff…

LINUX加固之命令审计

一、前言 在LINUX安全范畴中&#xff0c;安全溯源也是很重要的一个环节。对主机上所有曾操作过的命令详细信息需要有一份记录保存&#xff0c;当系统遭受破坏或者入侵&#xff0c;拿出这份记录&#xff0c;可以帮助定位一些可疑动作。 很多系统通常都会配置安全堡垒机&#xff…

jmeter断言-三种

1.响应断言 substring是指包含就行 不用完全相等 2.json断言 3.持续时间断言

Consule安装与SpringBoot集成

Consule Consul 是由 HashiCorp 开发的一款软件工具&#xff0c;提供了一组功能&#xff0c;用于服务发现、配置管理和网络基础设施自动化。它旨在帮助组织管理现代分布式和微服务架构系统的复杂性。以下是Consul的一些关键方面和功能&#xff1a; 服务发现&#xff1a;Consul…

2024第一篇: 架构师成神之路总结,你值得拥有

大家好&#xff0c;我是冰河~~ 很多小伙伴问我进大厂到底需要怎样的技术能力&#xff0c;经过几天的思考和总结&#xff0c;终于梳理出一份相对比较完整的技能清单&#xff0c;小伙伴们可以对照清单提前准备相关的技能&#xff0c;在平时的工作中注意积累和总结。 只要在平时…

【DevOps-02】Code编码阶段工具

一、简要说明 在code阶段,我们需要将不同版本的代码存储到一个仓库中,常见的版本控制工具就是SVN或者Git,这里我们采用Git作为版本控制工具,GitLab作为远程仓库。 Git安装安装GitLab配置GitLab登录账户二、Git安装 Git官网 Githttps://git-scm.com/

重新定义出行,PIX移动空间-Robobus2.0正式发布

PIX从创始之初就以重塑城市作为愿景&#xff0c;基于对未来终局的思考&#xff0c;我们重新定义了下一代汽车–移动空间&#xff0c;汽车不再只是一个交通工具&#xff0c;而是一个个提供服务的移动空间&#xff0c;这也将最终重塑城市&#xff0c;使城市成为一个真正的超级有机…

正定矩阵在格密码中的应用(知识铺垫)

目录 一. 写在前面 二. 最小值点 三. 二次型结构 四. 正定与非正定讨论 4.1 对参数a的要求 4.2 对参数c的要求 4.3 对参数b的要求 五. 最小值&#xff0c;最大值与奇异值 5.1 正定型&#xff08;positive definite&#xff09; 5.2 负定型&#xff08;negative defin…

【MySQL】字符集与排序规则

在MySQL数据库中&#xff0c;字符集&#xff08;Character Set&#xff09;和排序规则&#xff08;Collation,也称字符集校验规则&#xff09;是重要的概念&#xff0c;它们对于正确存储和比较数据至关重要。 字符集与排序规则 字符集是一组字符的集合&#xff0c;与数字编码…

8个流行的Python可视化工具包,你喜欢哪个?

用 Python 创建图形的方法有很多&#xff0c;但是哪种方法是最好的呢&#xff1f;当我们做可视化之前&#xff0c;要先明确一些关于图像目标的问题&#xff1a;你是想初步了解数据的分布情况&#xff1f;想展示时给人们留下深刻印象&#xff1f;也许你想给某人展示一个内在的形…

PostgreSQL从入门到精通 - 第40讲:数据库不完全恢复

PostgreSQL从小白到专家&#xff0c;是从入门逐渐能力提升的一个系列教程&#xff0c;内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容&#xff0c;希望对热爱PG、学习PG的同学们有帮助&#xff0c;欢迎持续关注CUUG PG技术大讲堂。 第40讲&#…

[足式机器人]Part2 Dr. CAN学习笔记-动态系统建模与分析 Ch02-4 拉普拉斯变换(Laplace)传递函数、微分方程

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-动态系统建模与分析 Ch02-4 拉普拉斯变换&#xff08;Laplace&#xff09;传递函数、微分方程 1. Laplace Transform 拉式变换2. 收敛域&#xff08;ROC&#xff09;与逆变换&#xff08;ILT&…

谷歌推出了一种名为提示扩展(Prompt Expansion)的创新框架,旨在帮助用户更轻松地创造出既高质量又多样化的图像。

谷歌推出了一种名为提示扩展&#xff08;Prompt Expansion&#xff09;的创新框架&#xff0c;旨在帮助用户更轻松地创造出既高质量又多样化的图像。 论文标题: Prompt Expansion for Adaptive Text-to-Image Generation 论文链接: https://arxiv.org/pdf/2312.16720.pdf 问…

拿到年终奖后马上辞职,厚道吗?

拿到年终奖后马上辞职&#xff0c;厚道吗&#xff1f; 作为一个人&#xff0c;你首先要对自己负责&#xff0c;其次是对自己身边的人&#xff08;妻儿&#xff0c;家人&#xff0c;朋友&#xff09;负责。 你明明可以跳槽到有更好的职业发展你不去&#xff0c;是为不智&#…

【普中开发板】基于51单片机的篮球计分器液晶LCD1602显示( proteus仿真+程序+设计报告+讲解视频)

基于普中开发板51单片机的篮球计分器液晶LCD1602显示 1.主要功能&#xff1a;讲解视频&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接资料下载链接&#xff08;可点击&#xff09;&#xff1a; 基于51单片机的篮球计分器液晶LCD1602显示 ( pr…

AspectJ入门(二)— 应用

AspectJ便于调试、测试和性能调整工作。定义的行为范围从简单的跟踪到分析&#xff0c;再到应用程序内部一致性到测试。AspectJ可以干净地模块化这类功能&#xff0c;从而可以在需要时轻松地启用和禁用这些功能。 1 基础 本节将继续介绍AspectJ到一些基础功能&#xff0c;为后…

水稻潜在产量估算解决方案

1.背景与技术路线 统计资料表明&#xff0c;尽管我国粮食单产已由 50 年代初期的 1.2t/ha 增加到如今的 5.2t/h&#xff0c;粮食产量增加了 4 倍&#xff0c;但我国人口的增长速度与气候变化导致的农业生产的不确定性&#xff0c; 在水稻收获指数保持稳定的情况下&#xff0c;…

drf知识--10

接口文档 # 后端把接口写好后&#xff1a; 登录接口&#xff1a;/api/v1/login ---> post---name pwd 注册接口 查询所有图书带过滤接口 # 前后端需要做对接&#xff0c;对接第一个东西就是这个接口文档&#xff0c;前端照着接口文档开发 公司3个人&#xff…