lc202.快乐数

 

题目链接

对于这个问题,印象中是用快慢指针的方法去判断有无环,但是具体怎么做已经记不清楚了。我看了一下官方题解,里面介绍了两种方法,把它们记录如下。

第一个方法是用哈希集合检测循环。我们先举几个例子,我们从7开始,下一个数是49,然后下一个数字是97,我们可以不断重复该过程,直到我们得到1。因为我们得到了1,我们知道了7是一个快乐数,函数返回true。而对于另外一个例子116,我们分别得到38,73,58,并且从58开始一个“58,89,145,42,20,4,16,37,58”的循环。所以对于116,函数会返回false。根据我们的推测,我们猜测会有以下三种可能。1.最终会得到1。2.最终会进入循环。3.值会越来越大,最后接近无穷大。第三种情况看起来比较难检测和处理,我们怎么知道它会继续变大,而不是最终得到1呢?我们再仔细思考一下,每一位数的最大数字的下一位是多少。再举几个例子,1位的数字最大为9,它在经历一次运算后是81;2位的数字最大是99,它在经历一次运算后是162;3位的数字最大是999,它在经历一次运算后为243;4位的数字最大是9999,它在经历一次运算后为324;13位的数字最大的是9999999999999,在经历一次运算后会变成1053。我们可以知道,对于3位的数,它不可能在运算过程中超过243,这意味着它要么被困在243以下的循环中,要么跌到1。4位或4位以上的数字在每一步都会丢失一位,直到降到3位为止。所以我们真的,最坏的情况下算法可能会在243以下的所有数字循环然后回到它已经到达过的一个循环或者回到1。但它不会无限期地进行下去,所以我们排除第三种情况。

现在只剩下前两种情况了。算法可以分成两部分,分别是1.给一个数字n,它的下一个数字是什么?2.按照一个系列的数字来判断我们是否进入了一个循环。第1部分我们做数位分离求平方和。第2部分可以使用哈希集合完成,每次生成下一个数字,我们都会检查它是否已经在哈希集合中。如果它不在哈希集合中,我们添加它,否则就意味着我们处在一个循环中,因此应该返回false。这个方法的时间复杂度是O(logN),空间复杂度是O(logN)。

第二个方法是快慢指针法。通过反复调用getNext(n)得到的是一个隐式的链表。既然有链表,问题就变成了判断链表是否有环。因此可以使用佛洛依德循环查找法。对于这种方法如2所示,时间复杂度为O(logN),空间复杂度为O(1)。

当然还有一个数学的方法,就是找到一个唯一的循环,在这里就不多说了。

python:

class Solution:
    def isHappy1(self, n: int) -> bool:
        
        def get_next(n):
            total_sum = 0
            while n > 0:
                n, digit = divmod(n, 10)
                total_sum += digit ** 2
            return total_sum
        
        seen = set()
        while n != 1 and n not in seen:
            seen.add(n)
            n = get_next(n)
        
        return n == 1
				
    def isHappy2(self, n: int) -> bool:
        
        def get_next(num):
            total_sum = 0
            while num > 0:
                num, digit = divmod(num, 10)
                total_sum += digit ** 2
            return total_sum
        
        slow, fast = n, get_next(n)
        while fast != 1 and slow != fast:
            slow = get_next(slow)
            fast = get_next(get_next(fast))
        return fast == 1