Floyd判圈算法(Floyd's cycle detection
Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm)。该算法由美国科学家罗伯特·弗洛伊德发明,是一个可以在有限状态机、迭代函数或者链表上判断是否存在环,求出该环的起点与长度的算法。
如果有限状态机、迭代函数或者链表上存在环,那么在某个环上以不同速度前进的2个指针必定会在某个时刻相遇。同时显然地,如果从同一个起点(即使这个起点不在某个环上)同时开始以不同速度前进的2个指针最终相遇,那么可以判定存在一个环,且可以求出2者相遇处所在的环的起点与长度。
算法描述
如果有限状态机、迭代函数或者链表存在环,那么一定存在一个起点可以到达某个环的某处(这个起点也可以在某个环上)。
初始状态下,假设已知某个起点节点为节点S。现设两个指针t和h,将它们均指向S。
接着,同时让t和h往前推进,但是二者的速度不同:t每前进1步,h前进2步。只要二者都可以前进而且没有相遇,就如此保持二者的推进。当h无法前进(或者是t,有一个就可以),即到达某个没有后继的节点时,就可以确定从S出发不会遇到环。反之当t与h再次相遇时,就可以确定从S出发一定会进入某个环,设其为环C。
如果确定了存在某个环,就可以求此环的起点与长度。
计算环长度
上述算法刚判断出存在环C时,显然t和h位于同一节点,设其为节点M。显然,仅需令h不动,而t不断推进,最终又会返回节点M,统计这一次t推进的步数,显然这就是环C的长度。
计算环起点
为了求出环C的起点,只要令h仍位于节点M,而令t返回起点节点S。随后,同时让t和h往前推进,且保持二者的速度相同:t每前进1步,h前进1步。持续该过程直至t与h再一次相遇,设此次相遇时位于同一节点P,则节点P即为从节点S出发所到达的环C的第一个节点,即环C的一个起点。
链表起点为节点S,环起点为节点P,t和h相遇时位于同一节点M,S和P之间的距离为p,P和M之间的距离为m,环长为C,这里两点之间的距离是指从一点走多少步可以到点另外一点。
当t和h相遇时,
t走的步数,step = p + m + a * C,a表示相遇时t走的圈数
h走的步数,2 * step = p + m + b * C,b表示相遇时h走的圈数
两者相减:step = (b - a) * C = p + m + a * C,由此可知t走的步数是环C的倍数,即 p + m 刚好是环长度C的倍数。
t和h在M处相遇,为了计算环C的起点,令h仍位于节点M,而令t返回起点S,随后,同时让t和h往前推进,且保持两者的速度相同:t每前进1步,h前进1步。持续该过程直至t与h再一次相遇,则它们此次相遇时一定位于环的起始节点P。为什么它们此次相遇时一定在环起始节点呢?
t走了p步到达P,h在环C上p步在哪呢?h从M处出发走了p步,相对于环起始位置,h走过的距离是 m + p,而m + p刚好是环长度C的倍数,即h此时也位于环起始节点处,即t和h在P处相遇。据此就可以计算出环起始节点的位置。
算法复杂度
时间复杂度
注意到当指针t到达环C的一个起点节点P时(此时指针h显然在环C上),之后指针t最多仅可能走1圈。若设节点S到P距离为,环C的长度为,则时间复杂度为,是线性时间的算法。
空间复杂度
仅需要创立指针t、指针h,保存环长n、环的一个起点P。空间复杂度为,是常数空间的算法。
应用
对于有限状态机与链表,可以判断从某个起点开始是否会返回到访问过运行过程中的某个状态和节点。
对于迭代函数,可以判断其是否存在周期,以及求出其最小正周期。
https://blog.csdn.net/javasus/article/details/50015687
```cpp
#include <bits/stdc++.h>
using namespace std;
int n ; //有n个节点
int len ; //循环节的长度
int start ; //链路的初始节点
int pos ; //循环节的初始节点
int val ; //初始节点的值
int m ; //在链路相遇的节点
int slow,fast; //两个速度指针
int f(int p){int next;//构造下一步方法return next;
}
bool floydcycle(int start, int len, int pos, int val){// 是否存在循环节 slow = f(start) ;fast =f( f(start) );int cnt=1;while(slow != fast && cnt < n){slow = f(slow);fast = f ( f(fast) );cnt++;}if(slow != fast) return false;// 循环节长度 len = 0;do{ slow = f(slow);len++;}while(slow != fast);//循环节起始位置slow = 0;int p=0;while(slow != fast){slow = f(slow);fast = f(fast);++p;} pos = p ;val = slow;
}
int main(){floydcycle( start, len, pos, val);
}
leetcode 202 快乐数
最终迭代下去,得到的和不管是不是1都是小于10的
https://leetcode-cn.com/problems/happy-number/
#include <bits/stdc++.h>
using namespace std;
class Solution{public:int f(int n){int ans=0;while(n){ans+=(n%10)*(n%10);n/=10;}return ans;}bool isHappy(int n){int slow = n;int fast = n;do{fast = f( f(fast) );slow = f(slow);}while(fast!=slow);if(slow != 1){return false;} else{return true;}}
};
int main(){Solution s;int n;cin>>n;if(s.isHappt(n)) cout<<"YES";else cout<<"NO"<<endl;return 0;
}
leetcode 141. Linked List Cycle
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {if(head==NULL)return false;ListNode *slow;ListNode *fast;slow = fast = head;do{slow = slow->next;fast = fast->next;if(fast!=NULL) fast = fast->next;}while( fast != NULL &&slow != NULL &&slow->val!=fast->val);if(fast==NULL || slow==NULL) return false;else return true;}
};
leetcode 142. Linked List Cycle II
测试数据
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *detectCycle(ListNode *head) {// T的飞起// ListNode *slow = head;// ListNode *fast = head;// if(head==NULL|| head->next==NULL ) return NULL; // do{// slow = slow->next;// //fast = fast->next;// if(fast->next != NULL){// fast = fast->next->next;// }// else {// return NULL;// }// }while(slow!=NULL && fast !=NULL && slow->val !=fast->val);// if(fast==NULL || slow==NULL)return NULL;bool isCycle = false;while(slow !=NULL && fast !=NULL){slow = slow->next;if(fast->next ==NULL) return NULL;fast=fast->next->next;if(slow == fast){isCycle = true;break;}}if(!isCycle) return NULL;slow=head;while(slow != fast){ //如果按照下面那种写法就过不了开始就是环的状态slow = slow->next;fast = fast->next;}// do{// slow = slow->next;// fast = fast->next;// }while(slow != fast);return slow;}
};
很能说明走到的相遇的位置和相遇的一道题
Floyd判圈算法(Floyd's cycle detection相关推荐
- leetcode202(Floyd判圈算法(龟兔赛跑算法))
Write an algorithm to determine if a number is "happy". 写出一个算法确定一个数是不是快乐数. A happy number ...
- floyd 判圈算法 UVa 11549 计算器谜题
题目http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- UVa 11549 Calculator Conundrum (训练指南,Floyd 判圈算法)
算法竞赛训练指南, 42 页 注意: 1. 用数组来记录一个数的各位的数字 2. 快慢指针来记录链表环的入点(Floyd 判圈算法) #include <cstdio> #include ...
- 如何判断链表中是否存在环?Floyd判圈算法 leetcode刷题笔记 142. 环形链表 II
这道题使用了floyd判圈算法,所以先讲解floyd算法的原理和实现,最后在附加上第142题的代码. floyd算法: 一.用途: 可以在有限状态机.迭代函数或者链表上判断是否存在环,求出该环的起点与 ...
- Calculator Conundrum UVA - 11549(floyd判圈)
Calculator Conundrum UVA - 11549 题意: 给你一个n和k. 每次操作可以把k平方,之后取k*k的前n位 为 k. 思路: 首先可以想到,经过有限次操作后,会出现循环. ...
- 弗洛伊德龟兔赛跑算法(弗洛伊德判圈算法)
弗洛伊德( 罗伯特・弗洛伊德)判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一个可以在有限状 ...
- floyd判环算法(龟兔赛跑算法)
floyd判环算法(龟兔赛跑算法) 注意,这个算法是用来判断一条链+一条环的图,环的长度或者环与链的交界处的,所以此floyd非彼floyd(虽然都是一个人想出来的). (图不是我的) 如果只要求环的 ...
- UVa11549计算器谜题[floyd判圈]
题意: 有个老式计算器,每次只能记住一个数字的前n位.现在输入一个整数k,然后反复平方,一直做下去,能得到的最大数是多少.例如,n=1,k=6,那么一次显示:6,3,9,1... 白书上的题 set, ...
- 消圈算法c语言,【图论】Floyd消圈算法
Definition&Solution 对于一个给定的链表,如何判定它是否存在环以及环的长度问题,可以使用Floyd消圈算法求出. 从某种意义上来讲,带环的链表在本质上是一个有向图 考虑下面的 ...
最新文章
- 【Live555】live555源码详解系列笔记
- php获取会员数据代码,php将会员数据导入到ucenter的代码
- OK6410裸机开发之LED灯
- numpy 笔记:setdiff1d
- 从mysql数据库中读取二进制文件_数据库技术之在MYSQL数据库中如何存取二进制文件...
- Toolbar+DrawerLayout
- pythonisodd函数_python3.5|小白入门基础语法之数据结构、函数、迭代,确实简洁...
- BZOJ 1257 [CQOI2007]余数之和sum ——Dirichlet积
- Android——SQLite实现面向对象CRUD
- Spring全自动AOP和项目加入jar包
- 理工男最该死的十二个瞬间
- selenium截取验证码图片
- Swift语法专题五——集合类型
- nodejs异常处理
- BAPI:KBPP_EXTERN_UPDATE_CO, TCODE:CJ30/CJ40 第二部分
- 步步为营 .NET三层架构解析 三、SQLHelper设计
- photoshop2022更新,新版PS新增了哪些功能Mac/win
- mysql中if多重判断使用
- 小菜鸟的自我激励与不服输的心
- ElasticSerach 出现 high disk watermark [90%] exceeded on