弗洛伊德的乌龟与兔子
Floyd
判圈算法(Floyd Cycle Detection Algorithm
),又称龟兔赛跑算法(Tortoise and Hare Algorithm
),是一个可以在有限状态机、迭代函数或者链表上判断是否存在环,以及判断环的起点与长度的算法。
结论
- 1、如果链表上存在环,那么在某个环上以不同速度前进的2个指针必定会在某个时刻相遇;
- 2、根据结论1找到的相遇点可找到环的入口,初始化额外的两个指针:
ptr1
,指向链表的头,ptr2
指向相遇点。然后,每次将它们往前移动一步,直到它们相遇,它们相遇的点就是环的入口。
结论1是很显然的,结论2似乎有点匪夷所思,下面将针对以上结论分别进行证明。
证明
1.龟兔相遇
一个跑得快的人和一个跑得慢的人在一个圆形的赛道上赛跑,会发生什么?在某一个时刻,跑得快的人一定会从后面赶上跑得慢的人。
下图说明了这个算法的工作方式。
初始状态下,假设已知某个起点节点为节点F。现设两个指针 fast
和 slow
,将它们均指向F。
同时让 fast
和 slow
往前推进,fast
的速度为 slow
的2倍),直到 fast
无法前进,即到达某个没有后继的节点时,就可以确定从F出发不会遇到环。反之当 fast
和 slow
再次相遇时,就可以确定从F出发一定会进入某个环,设其为环C( fast
和 slow
推进的步数差是环长的倍数)。
2.计算环的入口
如何找到环的入口?
根据结论1找到的相遇点可找到环的入口,初始化额外的两个指针:
ptr1
,指向链表的头,ptr2
指向相遇点。然后,每次将它们往前移动一步,直到它们相遇,它们相遇的点就是环的入口。
下图对结论2进行证明。
我们利用已知的条件:慢指针移动 1 步,快指针移动 2 步,来说明它们相遇在环的入口处:(下面证明中的 tortoise 表示慢指针,hare 表示快指针)
因为 F = b
,指针从 h
点出发和从链表的头出发,最后会遍历相同数目的节点后在环的入口处相遇。
算法描述
public class Solution {private ListNode getIntersect(ListNode head) {ListNode tortoise = head;ListNode hare = head;while (hare != null && hare.next != null) {tortoise = tortoise.next;hare = hare.next.next;if (tortoise == hare) {return tortoise;}}return null;
}public ListNode detectCycle(ListNode head) {if (head == null) {return null;}// 通过结论1,找到相遇点ListNode intersect = getIntersect(head);// 相遇点为空,则链表为非循环链表if (intersect == null) {return null;}// 通过结论2,找到环的入口// 分别定义两个指针,从head和相遇点开始前进,相遇点即为环的入口ListNode ptr1 = head;ListNode ptr2 = intersect;while (ptr1 != ptr2) {ptr1 = ptr1.next;ptr2 = ptr2.next;}return ptr1;}
}
- 时间复杂度:
O(n)
- 空间复杂度:
O(1)
例题
142. 环形链表 II
题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从0开始)。 如果 pos
是-1
,则在该链表中没有环。
说明:不允许修改给定的链表。
- 难度:
Medium
解题思路
经典的 Floyd
算法的应用场景。
public class Solution {public ListNode detectCycle(ListNode head) {if (head == null || head.next == null) return null;ListNode slow = head;ListNode fast = head;while (true) {if (fast == null || fast.next == null) {return null;}fast = fast.next.next;slow = slow.next;if (fast == slow) break;}fast = head;while (fast != slow) {fast = fast.next;slow = slow.next;}return fast;}
}
287. 寻找重复数 (Medium)
题目描述
给定一个包含 n + 1
个整数的数组 nums
,其数字都在 1
到 n
之间( 包括 1
和 n
),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
- 示例 1:
输入: [1,3,4,2,2]
输出: 2
- 示例 2:
输入: [3,1,3,4,2]
输出: 3
- 难度:
Medium
解题思路
正常的思路是通过 HashSet
, 或者通过排序以迅速找到重复数。
前者的时间和空间复杂度为 O(N)
,后者排序解决方案的时间复杂度为 O(NlogN)
空间复杂度为 O(1)
。
可以取巧的是,这道题因为题目的关系,可以将题目中数组视为 索引 与 对应值 的关系视为一个 链表,因为重复数的关系,它还是一个 循环链表,因此依然可以通过 Floyd
算法解决:
class Solution {public int findDuplicate(int[] nums) {int fast = nums[0];int slow = nums[0];// 找到相遇节点while (true) {slow = nums[slow];fast = nums[nums[fast]];if (slow == fast) {}}// 找到重复数int ptr1 = nums[0];int ptr2 = fast;while (ptr1 != ptr2) {ptr1 = nums[ptr1];ptr2 = nums[ptr2];}return ptr1;}
}
参考&感谢
- LeetCode-142:环形链表
- Wiki百科:Floyd判圈算法
关于我
Hello,我是 却把清梅嗅 ,如果您觉得文章对您有价值,欢迎 ❤️,也欢迎关注我的 博客 或者 Github。
如果您觉得文章还差了那么点东西,也请通过关注督促我写出更好的文章——万一哪天我进步了呢?
- 我的Android学习体系
- 关于文章纠错
- 关于知识付费
- 关于《反思》系列
弗洛伊德的乌龟与兔子相关推荐
- 快慢指针(LeetCode寻找重复数),弗洛伊德的乌龟和兔子
写此篇博客在于总结,记忆之用,欢迎评论补充. 弗洛伊德的乌龟和兔子,即快慢指针. 对于LeetCode287题,寻找重复数,题目如下: 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 ...
- 弗洛伊德的乌龟和兔子(循环检测
内容参考:https://www.jianshu.com/p/88c7e7a8de61 简短概述一下,就是一个大小为n+1的数组中,每个元素的大小范围为[1,n],该数组有且仅有一个重复数字,找出这个 ...
- 「兔了个兔」龟兔赛跑——乌龟和兔子能否相遇?
前言 森林里一年一度的赛跑大赛又开始了,乌龟和兔子又被分到了一组,这次乌龟还能跑过兔子吗? 比赛规则: 乌龟每次移动1个单元格,兔子每次移动2个单元格. 随机出现一条赛道,赛道可能为直线,也可能为含有 ...
- //多线程龟兔赛跑问题,乌龟和兔子比赛跑200米的距离,//名叫兔子的线程每执行一次兔子就向前跑5米,每跑50米休息10毫秒,//名叫乌龟的线程每执行一次乌龟就向前跑1米,乌龟会一直跑不休息/
//多线程龟兔赛跑问题,乌龟和兔子比赛跑200米的距离, //名叫兔子的线程每执行一次兔子就向前跑5米,每跑50米休息10毫秒, //名叫乌龟的线程每执行一次乌龟就向前跑1米,乌龟会一直跑不休息 // ...
- 【龟兔赛跑: 1、总里程100米 2、兔子每秒跑5米,每20米要休息2秒 3、乌龟每秒钟4米,不休息 4、谁先到达终点,比赛结束】
public class Zuoye2 {public static void main(String[] args) {//兔子的线程Thread rabbit = new Thread() {@O ...
- php实现狼和兔子,兔子和狼作文4篇
导语:下面兔子和狼,各位同学们会想出怎样精彩的故事呢?是小编为大家整理的兔子和狼作文,供大家阅读. 兔子和狼作文[1] 春天来了,暖融融的阳光驱走了寒冷,和煦的春风轻吻着大地.花儿开了,草儿绿了.一只 ...
- 【Leetcode】刷题之路2(python)
哈希映射类题目(简单题小试牛刀啦bhn) 242.有效的字母异位词 349.两个数组的交集 1002.查找常用字符 202.快乐数 383.赎金信 242. 有效的字母异位词 用python的Coun ...
- 蓝桥杯训练题目若干(东华20考研挑战题1-50)
文章目录 前言 1 Huffuman树 2 回文数 3 字母图形 4 大阶乘计算 5 回形取数 6 龟兔赛跑预测 7 Sine之舞 8 矩形面积交 9 矩阵乘法 10 分解质因数 11 字符串对比 1 ...
- PTA 基础编程题目集 7-22 龟兔赛跑 C语言
PTA 基础编程题目集 7-22 龟兔赛跑 C语言 乌龟与兔子进行赛跑,跑场是一个矩型跑道,跑道边可以随地进行休息.乌龟每分钟可以前进3米,兔子每分钟前进9米:兔子嫌乌龟跑得慢,觉得肯定能跑赢乌龟,于 ...
- 用C语言解“龟兔赛跑”题
7-22 龟兔赛跑 乌龟与兔子进行赛跑,跑场是一个矩型跑道,跑道边可以随地进行休息.乌龟每分钟可以前进3米,兔子每分钟前进9米:兔子嫌乌龟跑得慢,觉得肯定能跑赢乌龟,于是,每跑10分钟回头看一下乌龟, ...
最新文章
- 基于JSP/SERVLET实现的人脸识别考勤系统
- tomcat 和 jdk 版本 对应关系
- 【Android Gradle 插件】Android Plugin DSL Reference 离线文档下载 ( GitHub 下载文档 | 查看文档 )
- Linux中通过mkdir –p 能够创建多级目录(mkdir -p详解)
- 爱了!爱了!Markdown 必备组合神器!
- zookeeper集群配置说明以及window单台机器集群搭建
- 有关Botton的用法(二)
- 2016030206 - mysql常用命令
- sparkstreaming 读取mysql_SparkStreaming读取Kafka的两种方式
- kafka是如何解决粘包拆包的
- bzoj2150,poj1422,poj1548
- Linux查看文件第几行到第几行命令
- Android中继承的Dialog导致程序崩溃
- 如何在屏幕实时显示键盘操作(独家分享)
- slot的使用方法详解
- MTSP问题遗传算法解决及其代码与案例
- 如何用公式编辑器打半中括号?
- main java.lang,各位大哥办我看看,Exception in thread main java.lang.Error: 无法解析的编译有关问题...
- 【问链-区块链基础知识系列】 第十二课 区块链产业落地现状分析
- python 查看处理器架构
热门文章
- 财务管理系统-数据库模块
- Cesium orientation 和 设置初始角度
- 解决仙剑奇侠传“应用程序无法正常启动(0xc000000d)”的问题【转载】
- 空间相册怎么移到计算机里,qq空间上传照片_怎样把电脑里存的照片传到qq空间??...
- 谷歌AI平均每天发表2篇论文!Jeff Dean执笔年度汇总:16大方向
- Android 修改wifi阀值,6种简单方法使WiFi网络提速
- 【编程之美】读书笔记:寻找最大的K个数
- linux 搭建技术博客,Linux NTP服务器搭建精讲
- 亚马逊云服务(AWS)机器学习服务Amazon SageMaker发力中国
- 高通Hexagon通用计算DSP介绍