环形链表I、II(含代码以及证明)
环形链表
解题思路
- 定义两个指针,一个快指针,一个慢指针,快指针每次移动两个节点,慢指针每次移动一个节点。
- 从头节点开始,让快慢指针同时移动,如果链表中有环,那么快慢指针一定会在某个节点相遇。
- 如果快慢指针相遇了,说明链表中有环,返回true。如果快指针移动到了null,说明链表中没有环,返回false。
思考1:为什么快慢指针能判断是否有环
- 如果链表中没有环,那么快指针会先于慢指针到达链表的尾部,也就是null,这时候我们就可以判断链表中没有环,返回false。
- 如果链表中有环,那么快指针会在环中不断地追赶慢指针,就像两个人在环形跑道上跑步,速度快的人总会追上速度慢的人。这时候,快指针和慢指针一定会在某个节点相遇,这时候我们就可以判断链表中有环,返回true。
- 为什么快指针要每次移动两个节点,慢指针要每次移动一个节点呢?这是为了保证快指针和慢指针的相对速度是一定的,如果快指针每次移动三个节点,慢指针每次移动一个节点,那么快指针的速度就是慢指针的三倍,这样可能会导致快指针在环中跳过慢指针,从而无法相遇。如果快指针每次移动一个节点,慢指针每次移动一个节点,那么快指针和慢指针的速度就是一样的,这样也无法相遇。所以,快指针每次移动两个节点,慢指针每次移动一个节点,是一种比较合理的选择,可以保证快慢指针在环中一定会相遇。
代码实现
// 定义一个判断链表是否有环的方法,接受一个头节点作为参数
public boolean hasCycle(Node head) {
// 如果头节点为空,直接返回false
if (head == null) {
return false;
}
// 定义快慢指针,初始化为头节点
Node fast = head;
Node slow = head;
// 用一个循环来移动快慢指针
while (fast != null && fast.next != null) {
// 快指针每次移动两个节点
fast = fast.next.next;
// 慢指针每次移动一个节点
slow = slow.next;
// 如果快慢指针相遇了,说明有环,返回true
if (fast == slow) {
return true;
}
}
// 如果快指针移动到了null,说明没有环,返回false
return false;
}
环形链表II
解题思路
- 定义两个指针,一个快指针fast,一个慢指针slow,都从头节点head开始遍历链表。
- 快指针每次走两步,慢指针每次走一步,如果链表有环,那么快慢指针一定会在环内相遇,否则快指针会先遍历完链表(遇到null)。
- 如果快慢指针相遇,说明链表有环,此时将快指针重新指向头节点head,慢指针保持在相遇节点,然后快慢指针都每次走一步,直到再次相遇,相遇的节点就是入环的第一个节点。即:从头节点到入环节点的距离,等于从相遇节点继续走到入环节点的距离。
- 如果快慢指针没有相遇,说明链表无环,返回null。
举个例子:
1 -> 2 -> 3 -> 4
^ |
| v
7 <- 6 <- 5
- 这个链表中有一个环,从节点2到节点7。环的长度是6,入口节点是节点2。
- 我们可以用快慢指针的方法,让快指针从节点1开始,每次走两步,慢指针从节点1开始,每次走一步,它们在节点7相遇,然后让快指针从头开始一步步走,慢指针保持在相遇节点开始一步步走,快慢指针再次在2节点相遇,所以2节点就是入环节点。
思考1:为什么慢指针每次移动一步,快指针每次移动两步,一定会在环中相遇而不是错过?
假设链表的长度是L,环的长度是n,环的入口节点距离头节点的距离是a,快慢指针在环中相遇的节点距离环的入口节点的距离是b,那么有以下关系:
- 当快慢指针相遇时,慢指针走过的距离是a+b,快指针走过的距离是a+b+k*n,其中k是快指针在环中绕的圈数。
- 因为快指针的速度是慢指针的两倍,所以快指针走过的距离是慢指针的两倍,即2*(a+b) = a+b+kn,化简得a+b = kn。
- 这个式子的意思是,当快慢指针相遇时,慢指针走过的距离刚好是环的长度的整数倍,也就是说,慢指针在环中走了k圈,快指针在环中走了k+1圈。
- 这样,我们可以知道,快慢指针一定会在环中相遇,而不是错过,因为快指针每次都会比慢指针多走一步,所以它们之间的距离每次都会缩小一步,直到相遇为止。
思考2:如何证明,从头节点到入环节点的距离,等于从相遇节点继续走到入环节点的距离?
假设从头结点到环形入口节点的距离为x。 环形入口节点到fast指针与slow指针相遇节点距离为y。从相遇节点再到环形入口节点距离为z
- 当快慢指针首次相遇时,慢指针走过的路程为x + y,快指针走过的路程为x + y + n (y + z)。
- 由于快指针的速度是慢指针的两倍,所以快指针走过的路程是慢指针的两倍,即(x + y) * 2 = x + y + n (y + z)。
- 化简得到x + y = n (y + z),即x = n (y + z) - y,再从n(y+z)中提出一个(y+z)来,得到x = (n - 1) (y + z) + z。而 y + z正好是环一圈的长度。
- 这个式子的意义是,从头节点到入环节点的距离,等于快慢指针相遇后,一个指针继续走n-1圈,再加上从相遇点到入环节点的距离。
- 当n=1时,即某一指针只走了一圈,那么x = z,即从头节点到入环节点的距离,等于从相遇节点继续走到入环节点的距离。
- 因此,如果我们让一个指针从头节点开始,另一个指针从相遇节点开始,每次都走一步,那么他们最终会在入环节点相遇,这样就找到了入环节点。
代码实现
public ListNode detectCycle(ListNode head) {
//如果链表为空或只有一个节点,直接返回null
if (head == null || head.next == null) {
return null;
}
//定义快慢指针
ListNode fast = head;
ListNode slow = head;
//遍历链表,直到快指针遇到null或快慢指针相遇
while (fast != null && fast.next != null) {
//快指针走两步,慢指针走一步
fast = fast.next.next;
slow = slow.next;
//如果快慢指针相遇,说明有环
if (fast == slow) {
//将快指针重新指向头节点
fast = head;
//快慢指针都每次走一步,直到再次相遇
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
//返回相遇的节点,即入环的第一个节点
return fast;
}
}
//如果快指针遇到null,说明无环,返回null
return null;
}
环形链表I、II(含代码以及证明)的更多相关文章
- 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II
今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...
- LeetCode142 环形链表 II
给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? //章节 - 链表 //二.双指针技巧 //2.环 ...
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- Leetcode 142.环形链表II
环形链表II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? 链表头是X,环的第一个节点是Y,sl ...
- LeetCode 142:环形链表 II Linked List Cycle II
给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...
- Leetcode.142-Linked-list-cycle-ii(环形链表II)
环形链表II 思路 https://www.cnblogs.com/springfor/p/3862125.html https://blog.csdn.net/u010292561/article/ ...
- LeetCode 142. 环形链表 II(Linked List Cycle II)
142. 环形链表 II 142. Linked List Cycle II 题目描述 给定一个链表,返回链表开始入环的第一个节点.如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整 ...
- Java实现 LeetCode 142 环形链表 II(二)
142. 环形链表 II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始 ...
- [LeetCode题解]142. 环形链表 II | 快慢指针
解题思路 本题是在141. 环形链表基础上的拓展,如果存在环,要找出环的入口. 如何判断是否存在环,我们知道通过快慢指针,如果相遇就表示有环.那么如何找到入口呢? 如下图所示的链表: 当 fast 与 ...
- 【LeetCode】142. 环形链表 II
142. 环形链表 II 知识点:链表:set:快慢指针 题目描述 给定一个链表,判断链表中是否有环. 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表 ...
随机推荐
- uniapp 实现小程序中自定义tabBar 的方法
uniapp 实现小程序中自定义tabBar 的方法 第一种方式: page.json中配置 "tabBar": { "color": "#7A7E8 ...
- oracle第二步创建表空间、用户、授权
Windows+r→键入sqlplus,输入已安装好的oracle数据库超级管理员账号密码登录.显示: 成功. 创建表空间: 创建用户并默认表空间: 授权该创建用户对数据库的操作: 代码: SQL&g ...
- beanshell报错:Error invoking bsh method: eval解决办法(beanshell 不支持Java中的泛型)
起因:在beanshell中读取CSV文件中的内容,相同的代码在IDEA中可以执行通过,但是在beanshell中报错: ERROR o.a.j.u.BeanShellInterpreter: Err ...
- nginx配置文件讲解及示例(可复制)
详细的配置说明参考:https://www.cnblogs.com/ghl1024/p/9013805.html [示例一] #运行用户user www-data; #启动进程,通常设置成和cpu ...
- uni 结合vuex 编写动态全局配置变量 this.baseurl
在日常开发过程,相信大家有遇到过各种需求,而我,在这段事件便遇到了一个,需要通过用户界面配置动态接口,同时,因为是app小程序开发,所以接口中涉及到了http以及websocket两个类型的接口. 同 ...
- 环境安装-Centos7.4安装及配置
环境安装-Centos7.4安装及配置 〇.资料汇总 一.虚拟机安装 1.下载地址 https://pan.baidu.com/s/1zcOp06HX4OxPdsCCGkHbXQ 提取码:7777 2 ...
- 【大数据面试】【框架】kafka:组成、台数/参数配置、持久化、ISR队列、宕机、丢数据、重复数据、数据积压、优化各种配置(刷盘、存盘、副本、压缩)、zk、其他
一.基本信息 1.组成 生产者 broker 消费者 zookeeper:brokerid.consumer信息(不包含生产者的信息) 2.需要安装多少台 2 * (生产者的峰值生产速率 * 副本 / ...
- 关于Mybatis-Plus中update()、updateById()方法的使用及null值的判断
使用场景说明: 在 Mybatis-Plus 的使用过程中,经常会遇对数据库更新的情况 更新常用方法:update().updateById() 问题:经常会遇见对 null 值的处理,对传入的实体参 ...
- 常用内置模块os sys json
今日内容回顾 目录 今日内容回顾 os模块 sys模块 json模块 json模块实战 os模块 sys模块 json模块 os模块 os模块主要与代码运行的操作系统打交道 1.创建目录(文件夹) i ...
- [seaborn] seaborn学习笔记6-热图HEATMAPPLOT
6 热图Heatmapplot(代码下载) 热图是指通过将矩阵单个的值表示为颜色的图形表示.热力图显示数值数据的一般视图非常有用,制作热图很简单,且不需要提取特定数据点.在seaborn中使用heat ...