判断环形链表是否有环??返回环形链表的入口点

news2024/11/26 14:37:59

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1

输出:true

解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0

输出:true

解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1

输出:false

解释:链表中没有环。

提示:

链表中节点的数目范围是 [0, 104]

-105 <= Node.val <= 105

pos 为 -1 或者链表中的一个 有效索引 。
复制代码

进阶:你能用 O(1)(即,常量)内存解决此问题吗?

上述是力扣中的题目!如果你已经看完了题目,那么,就该跟着笔者进入正文解析了!!

根据链表的基础知识,我们可以得出:如果一个链表是环形链表,那么最后一个节点一定存储了前面某个节点的地址!!

思路:快慢指针:

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表的起始位置(头节点)开始进行,如果链表带环,则快指针与慢指针一定会在环中相遇!!否则,快指针一定会率先走到链表的尾部,比如,陪女朋友到操场跑步减肥!!

扩展问题:

为什么快指针一次走两步,慢指针一次走一步可以??
复制代码

假设链表带环,两个指针最后都会进入环,快指针先进入环,慢指针后进入环,当慢指针刚进入环时候,可能就与快指针相遇了,最差的情况下,两个指针的距离就是环的长度!此时两个指针每移动一次,之间的距离就缩小一步,,不会出现每次刚好是套圈的情况,因此,在慢指针走一圈之前,快指针肯定可以追上慢指针的!即相遇!

2.快指针一次走3步,走4步,...n步行吗? 假设有环的情况下:快指针每次走3步,慢指针每次走1步,此时快指针肯定先进环,慢指针后来才进环,假设慢指针进环的时候,快慢指针的相对位置如图所示:

此时按照上述的假设:快指针每次走3步,慢指针每次走1步,来绕环移动,是永远不会相遇的!!此时进行了套圈!!

因此,只有快指针走2步,慢指针走1步才可以,换的是最小长度是1,即使套圈了,两个也能在相同位置!!

此时我们可以看出,环的问题,可以大致理解为:追及相遇的问题!!

那么,有了这些想法,我们还应该判断没环的情况下的问题:

经过上述的分析,我们可以看出当没环条件下的结束条件!

因此,我们有着下述的简单代码:写法1:

     public boolean hasCycle(ListNode head){
        ListNode fast=head;
        ListNode slow=head;
        while (fast != null && fast.next !=null){  //没环的情况下!
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){
                return true;
            }
        }
        return false;
    }
复制代码

写法2:

     public boolean hasCycle2(ListNode head){
        ListNode fast=head;
        ListNode slow=head;
        while (fast != null && fast.next !=null){
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){
                break;//出while循环(有两种可能)
            }
        }
        if (fast==null ||fast.next==null){//排除不是环的可能
            return false;
        }
            return true;       
    }
复制代码

经过这个题目,我们可以思考一下,如何进行手动置环??

手动置环问题:遍历一遍链表,找到尾巴节点,其所对应的next本为null,将其改为前面任意节点的地址就可以了(保证有)!!

   //手动置环
    public void creatLoop(ListNode head){
        ListNode cur=head;
        while (cur.next !=null){
            cur=cur.next;//找尾巴节点
        }
        cur.next=head.next.next;//保证有该节点!
    }
复制代码
  1. 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1

输出:返回索引为 1 的链表节点

解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0

输出:返回索引为 0 的链表节点

解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1

输出:返回 null

解释:链表中没有环。

提示:

链表中节点的数目范围在范围 [0, 104] 内

-105 <= Node.val <= 105

pos 的值为 -1 或者链表中的一个有效索引
复制代码

进阶:你是否可以使用 O(1) 空间解决此题?

对于这个题目,显得有点儿难度!!

结论 让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。 证明

这个是主要的思路,或许你看不懂,没关系,那么请看一下笔者的推论吧!!

我们有着以下的简单思路:

1.当在最好的情况下:我们有着:fast多走一圈,然后与slow在相遇处相遇,此时,fast走的路程为:X+C(C-Y) 此时,slow走的路程:X+(C-Y),由于fast的速度是slow的二倍,则路程也是2倍,即有着一下结论:2*(X+C-Y)=X+C+(C-Y) 经过计算,我们可以得到;X==Y

2.当不最好的情况下:fast走了很多圈,才与slow在相遇点相遇,此时说明,环的长度C很小很小!!

此时,fast走的路程为:X+NC(C-Y) 此时,slow走的路程:X+(C-Y),由于fast的速度是slow的二倍,则路程也是2倍,即有着一下结论:2*(X+C-Y)=X+NC+(C-Y) 经过计算,我们可以得到;X==(N-1)*C+Y 因此,当N很大很大的时候,说明环很小很小了,而fast多走的长是从相遇点开始的!!

注意:

当慢指针进入环时候,快指针可能已经在环中绕了N圈了,N至少为1,因为当快指针先到环走到相遇点的位置,慢指针还没有进环!

慢指针进入环以后,快指针肯定会在慢指针走一圈之内追上慢指针,因为:快指针进环之后,快慢指针之间的距离最多就是环的长度,而两个指针在移动的时候,每次他们之间的距离都会缩减1步,因此,慢指针移动一圈之前,快指针一定可以追上慢指针的!!
复制代码

下面请看笔者的代码吧!!代码很简单,但是思路很重要!!

 //返回循环链表的相交节点
    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){
                break;
            }
        }
        if (fast == null || fast.next == null){
            return null;
        }
        //此时fast与slow已经在相遇点相遇了!
        slow=head;//将fast或者slow任意一个拉回头节点head
        while (fast !=slow){
            fast=fast.next;
            slow=slow.next;
        }//当fast与slow再次相遇的时候,即为入口点
        return fast;
    }
复制代码

对于这个代码,想必各位老铁都能看懂吧!!

由于在码字的过程中,出现了些许差错,导致有点错别字!!勿怪!勿怪!

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

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

相关文章

IDEA插件-MavenHapler

1.安装Maven Helper Maven Helper 是 IntelliJ IDEA 中的一个插件&#xff0c;可以帮助您管理 Maven 依赖项。它可以帮助您更容易地删除不再需要的依赖项&#xff0c;查看依赖项的冲突&#xff0c;以及执行其他有关 Maven 依赖项的操作。 打开 IDEA 设置页面&#xff1a; 在插…

gpu超频超额训练导致电源关机

详细原理参见&#xff1a; 离显卡功耗实标还有多远&#xff1f;峰值功耗与电源关系终结篇 – FCPOWERUP极电魔方 和 【硬件科普】如何合理科学的选择电源功率的大小&#xff1f;_哔哩哔哩_bilibili 本人的1250w电源截图&#xff1a; 分析&#xff1a; 12V输出分了6路&#xff…

游戏逆向_Android读写游戏内容

一、背景 Android外挂的实现&#xff0c;需要涉及相应游戏内容的读写。读写的游戏内容包括代码和数据 针对不同的读写对象&#xff0c;通用的步骤就是寻找对象地址&#xff08;位置&#xff09;→获取相应权限→读写。下面将更详细介绍下相关实现。 二、实现方式 实现方式可…

了解最新的Android开发趋势和技术的秘诀

前言 当前&#xff0c;Android开发市场已经相当成熟&#xff0c;并且在全球范围内都非常活跃。Android是全球最受欢迎的移动操作系统之一&#xff0c;自Android开源以来&#xff0c;它已经改变了移动技术。市场上大量的企业和开发者都在积极地跟进、深入研究和开发Android系统…

大数据Flink进阶(十二):Flink本地模式开启WebUI

文章目录 Flink本地模式开启WebUI 一、在Flink 项目中添加本地模式 WebUI的依赖

2023 Java面试题短期突击攻略,已帮助400+位程序员成功拿到offer

2023春招已经开始一段时间了&#xff0c;很多同学会问Java面试八股文有必要背吗&#xff1f; 我的回答是&#xff1a;很有必要。你可以讨厌这种模式&#xff0c;但你一定要去背&#xff0c;因为不背你就进不了大厂。 国内的互联网面试&#xff0c;恐怕是现存的、最接近科举考试…

让PyTorch训练速度更快,你需要掌握这17种方法

掌握这 17 种方法&#xff0c;用最省力的方式&#xff0c;加速你的 Pytorch 深度学习训练。近日&#xff0c;Reddit 上一个帖子热度爆表。主题内容是关于怎样加速 PyTorch 训练。原文作者是来自苏黎世联邦理工学院的计算机科学硕士生 LORENZ KUHN&#xff0c;文章向我们介绍了在…

利用Chat GPT建立一个To-Do应用程序--我们终于遇到了我们的替代者吗?

海外Udemy、Coursera、Skillshare、Cantrill等平台精品编码课程&#xff0c;请访问 https://www.postcode.vip 我们看到GitHub Copilot在2021年10月发布&#xff0c;整个开发社区都疯了。 有些人声称我们很快就会失去工作&#xff0c;而其他人&#xff0c;像我一样&#xff0…

首家完成并购并进行重新备案公示的企业征信牌照公司-湖南省征信

2023年4月13日&#xff0c;中国人民银行长沙中心支行发布《关于对湖南省征信有限公司企业征信机构变更备案的公示》。内容显示中国人民银行长沙中心支行根据《征信业管理条例》《征信机构管理办法》《企业征信机构备案管理办法》及有关规定&#xff0c;决定受理湖南省征信有限公…

小程序学习四--组件--样式、数据、方法、属性、数据监听、生命周期、插槽、behavior

一、自定义组件 1.创建组件 2.组件引用--局部引用 3.组件引用--全局引用 4.组件和页面的区别 5.修改组件胡样式隔离选项 stypelsolation的可选值 二、自定义组件数据、方法、属性和数据监听 1.data数据 2.methods方法 事件处理函数、自定义方法_ 3.properties属性 页面中调…

JVM 内存结构

文章目录1、程序计数器2、虚拟机栈2.1 、定义2.2、栈内存溢出2.3 、线程运行诊断3、本地方法栈4、堆4.1、定义4.2 、堆内存溢出4.3 、堆内存诊断5、方法区&#xff08;Method Area&#xff09;5.1 、定义5.2、方法区组成5.3 、方法区内存溢出5.4 、运行时常量池5.5 、StringTab…

【JavaEE】TCP网络原理

目录 1.TCP协议定义 2.TCP原理 2.1确认应答机制 2.2超时重传机制 2.3连接管理 2.3.1建立连接&#xff08;三次握手&#xff09; 2.3.2断开连接&#xff08;四次挥手&#xff09; 2.4滑动窗口 2.5流量控制 2.6拥塞控制 2.7延迟应答 2.8捎带应答 2.9面向字节流&…

【STC8A8K64D4开发板】——按键检测

第2-3讲&#xff1a;按键检测 学习目的学习轻触按键和触摸按键硬件电路原理。学习STC8A8K64D4用作输入时相关寄存器的配置。掌握如何读取GPIO状态。掌握编写轻触按键和触摸按键检测程序。 硬件电路设计 IK-64D4开发板上设计了4个轻触按键和一个触摸按键&#xff0c;提供给用户作…

企业级信息系统开发讲课笔记2.3 利用MyBatis实现关联查询

文章目录零、本节学习目标一、查询需求&#xff08;一&#xff09;针对三张表关联查询&#xff08;二&#xff09;按班级编号查询班级信息&#xff08;三&#xff09;查询全部班级信息二、创建数据库表&#xff08;一&#xff09;创建教师表&#xff08;二&#xff09;创建班级…

BUUCTF-WEB-INF/web.xml泄露-SSTI注入

第八周 目录 WEB [RoarCTF 2019]Easy Java WEB-INF/web.xml泄露 WEB-INF/web.xml泄露原因 WEB-INF/web.xml泄露利用方法 解决方法 [BJDCTF2020]The mystery of ip 什么是板块注入 SSTI 为什么会产生 什么是render_template render_template&#xff1a; 我们为什么…

背包问题-动态规划

背包问题 容量有限的背包&#xff0c;给很多商品&#xff0c;商品有相应的体积与价值 01背包问题 一个背包 每个物品只有一个 最终状态方程 dp[i][j]max(dp[i-1][j],dp[i-1][j-w[i]]v[i]) 推导过程 由上一层推导过来 选择拿不拿i 最终代码 #include<iostream> #…

第12届蓝桥杯省赛真题剖析-2020年12月20日Scratch编程中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第124讲。 第12届蓝桥杯省赛举办了两次&#xff0c;这是2020年10月20日举行的第一次省赛中级组试题&#xff0c;比赛仍…

【Java实战篇】Day6.在线教育网课平台

文章目录一、需求&#xff1a;绑定媒资1、需求分析2、库表设计与模型类3、接口定义4、Mapper层开发5、Service层开发6、完善controller层二、需求&#xff1a;课程预览1、需求分析2、实现技术3、模板引擎4、Freemarker入门5、部署网站门户6、接口定义7、接口开发8、编写模板9、…

放弃 console.log 吧!用 Debugger 你能读懂各种源码

很多同学不知道为什么要用 debugger 来调试&#xff0c;console.log 不行么&#xff1f; 还有&#xff0c;会用 debugger 了&#xff0c;还是有很多代码看不懂&#xff0c;如何调试复杂源码呢&#xff1f; 这篇文章就来讲一下为什么要用这些调试工具&#xff1a; console.lo…

PostgreSQL技术内幕(七)索引扫描

索引概述 数据库索引&#xff0c;是将一个表的某些字段的数据进行重新组织的数据库对象。通过使用索引&#xff0c;可以大大加速数据库的一些操作&#xff0c;其背后的思想也很简单朴素&#xff1a;空间换时间。 数据库中的索引&#xff0c;可以类比为一本书的目录&#xff0…