您的位置:首页 > 移动开发

Floyd判圈算法 leetcode 202题Happy Number

2018-03-01 18:34 369 查看
今天,日常刷leetcode,遇到202问题如下:
Write an algorithm to determine if a number is "happy".A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.Example: 19 is a happy number
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
Credits:
Special thanks to @mithmatt and @ts for adding this problem and creating all test cases.题目大意是输入一个正数,不断求其各位数字的平方和,如果最后得到的平方和为1则为“happy number”,若计算出的平方和各中间状态出现无限循环,则这个数不是“happy number”。
做这个题的主流思路是利用循环不断求所给正数的各位数字平方和,并利用Set记录每个中间结果,利用两个标准来控制循环的进行:
1. 所求得的各位数字平方和是否为1,若为1,返回结果;
2. 所求得的平方和是否与Set中已有的某个状态一致,如果出现相同的平方和,说明出现了循环,返回结果;
具体实现代码如下:



这个思路是比较容易理解的, 利用Set的特性来判断是否出现了循环。
但是这个题有更好的解决方法,利用了 Floyed判圈算法,代码如下:



代码比较容易懂,就是找到求平方和过程中出现闭环的部分。我不明白的地方在于,假设输入的正数状态为编号为1,后续n次求得的平方和为2到n,那么第一次slow和fast比较的是状态2和状态3,第二次为3和5,第三次为4和7,第四次为5和9,即每次比较,比较的两个状态为n和2n-1,我不明白为什么要这样比较。
查阅了维基百科对该算法的解释如下:
Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一个可以在有限状态机迭代函数或者链表上判断是否存在,求出该环的起点与长度的算法。该算法据高德纳称由美国科学家罗伯特·弗洛伊德发明,但这一算法并没有出现在罗伯特·弗洛伊德公开发表的著作中[1]。如果有限状态机、迭代函数或者链表上存在环,那么在某个环上以不同速度前进的2个指针必定会在某个时刻相遇。同时显然地,如果从同一个起点(即使这个起点不在某个环上)同时开始以不同速度前进的2个指针最终相遇,那么可以判定存在一个环,且可以求出2者相遇处所在的环的起点与长度。具体算法描述:如果有限状态机、迭代函数或者链表存在环,那么一定存在一个起点可以到达某个环的某处(这个起点也可以在某个环上)。初始状态下,假设已知某个起点节点为节点S。现设两个指针t和h,将它们均指向S。接着,同时让t和h往前推进,但是二者的速度不同:t每前进1步,h前进2步。只要二者都可以前进而且没有相遇,就如此保持二者的推进。当h无法前进,即到达某个没有后继的节点时,就可以确定从S出发不会遇到环。反之当t与h再次相遇时,就可以确定从S出发一定会进入某个环,设其为环C。如果确定了存在某个环,就可以求此环的起点与长度。上述算法刚判断出存在环C时,显然t和h位于同一节点,设其为节点M。显然,仅需令h不动,而t不断推进,最终又会返回节点M,统计这一次t推进的步数,显然这就是环C的长度。为了求出环C的起点,只要令h仍均位于节点M,而令t返回起点节点S,此时h与t之间距为环C长度的整数倍。随后,同时让t和h往前推进,且保持二者的速度相同:t每前进1步,h前进1步。持续该过程直至t与h再一次相遇,设此次相遇时位于同一节点P,则节点P即为从节点S出发所到达的环C的第一个节点,即环C的一个起点。
在另一篇博客上,我找到了相关公式的推导:http://blog.csdn.net/javasus/article/details/50015687



通过对原理的理解,之所以slow选用步长1,fast选用步长2,是为了在出现环的情况下能让fast赶上slow,在这个题只需要判断是否有环,那么只要fast的步长比slow的步长长即可,为了验证我把代码改为:



也通过了。
Floyd算法还有很多点值得去探究,在后续用到的时候再研究。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: