快乐数死循环4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4

最近刷leetcode遇到的一个问题:

leetcode#202 快乐数
编写一个算法来判断一个数是不是“快乐数”。
一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。

看到很多人提到的4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4死循环理论和数字 1 和 7 ,我就很想不通这个规律是怎么得到的,于是我用python试了试怎么得出来的。

思路:

这个循环显然是之前有人试出来的,所以我就从2开始观察,对每个数按照平方和的结果与起点对比,因为大部分是死循环,所以我设置了最大循环次数是1000,如果循环了1000次回不到起点,我们就认为不会回到起点了,大家有兴趣的可以把这个上限调高点再去观察。

下面是代码,注释很清楚了:
# 新建一个计算各位数平方之和的函数
def numSum(num):
	nSum = 0
	while num:
		nSum += (num % 10) **2
		num = num // 10
	return nSum
观察每个数每个数能否回到起点,有了这一步才能得出下一步的结果
if __name__ == '__main__':
    #****************************** 训练模型得出死循环 ******************************#
    # 1就没必要观察了,直接从2开始
    num = 2
    # 这个列表用来存不快乐数
    loopNumList = []
    # 要观察的最大数字是多少
    maxNum = 1000
    # 下面开始训练
    while num < maxNum:
        # 这里用tmp替换n运算,因为后面对比要用到原始数字n,所以不要对n修改
        tmp = num
        # 循环计数,以及最大循环次数,1000次没有回到起点,应该就差不多认为不会回到起点了,你也可以自行调整
        # 一定要用最大循环次数,要不然会死循环
        counts = 1
        maxLoops = 1000
        while counts < maxLoops:
            tmp = numSum(tmp)
            if numSum(tmp) == num:
                print("%s 循环了 %s 次回到起点" % (num, counts))
                loopNumList.append(num)
                # 一旦检测到回到起点了,就要跳出循环,检测下一个数
                break
            counts += 1
        # else:
        # 	print("%s 循环了 %s 没有回到起点" % (num, counts))
        num += 1
    print()
    print("%s 以内的死循环: " % maxNum)
    print(loopNumList)
output:
4 循环了 7 次回到起点
16 循环了 7 次回到起点
20 循环了 7 次回到起点
37 循环了 7 次回到起点
42 循环了 7 次回到起点
58 循环了 7 次回到起点
89 循环了 7 次回到起点
145 循环了 7 次回到起点

1000 以内的死循环: 
[4, 16, 20, 37, 42, 58, 89, 145]
我现在才有点思路那些人是怎么得到这个神奇的死循环,直接给出4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4的循环结果:
if __name__ == '__main__':

    # 这里是为展示4的循环路径,因为我已经通过下面的过程知道了4会进入死循环
    unHappyNum = 4
    while 1:
        unHappyNum = numSum(unHappyNum)
        print(unHappyNum, end = "——>")
        if numSum(unHappyNum) == 4:
            break
output
16——>37——>58——>89——>145——>42——>20——>
有了上面的思路,我们很轻易就能得出指定区间内所有的快乐数:
if __name__ == '__main__':
    #****************************** 训练模型得出快乐数 ******************************#
    #有了上面的思路,只需要把 if numSum(tmp) == num 中的 num 改为 1 就可以得到区间内所有的快乐数
    num = 1
    # 这个列表用来存快乐数
    happyNumList = []
    # 要观察的最大数字是多少
    maxNum = 300
    while num < maxNum:
        tmp = num
        counts = 1
        maxLoops = 1000
        while counts < maxLoops:
            tmp = numSum(tmp)
            if numSum(tmp) == 1:
                # print("%s 循环了 %s 次回到起点" % (num, counts))
                happyNumList.append(num)
                break
            counts += 1
        num += 1
    print("%s 以内的快乐数: " % maxNum)
    print(happyNumList)
output
300 以内的快乐数: 
[1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262, 263, 280, 291, 293]
最后附上我的解法,是用的死循环理论,耗时有点久:
class Solution {
    public boolean isHappy(int n) {
        List<Integer> unHappy = Arrays.asList(4,16,37,58,89,145,42,20);
        if (n <= 0) {
            return false;
        }
        while(n != 1) {
            n = numSum(n);
            if (unHappy.contains(n)) {
                return false;
            }
        }
        return true;
    }
    
    private int numSum(int x) {
        int ret = 0;
        while (x > 0) {
            ret += (x%10) * (x%10);
            x /= 10;
        }
        return ret;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值