LeetCode 快乐数

题目

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

示例

input: 19
output: true
解释:
    1^2 + 9^2 = 82
    8^2 + 2^2 = 68
    6^2 + 8^2 = 100
    1^2 + 0^2 + 0^2 = 1

解法


Set ( Python )
class Solution:
    def isHappy(self, n: int) -> bool:
        s = set()
        res = n
        while(res != 1):
            res = self.calPowSum(res)
            if(res in s):
                return False
            else:
                s.add(res)
        return True

    def calPowSum(self, n: int) -> int:
        sum = 0
        while(n > 0):
            sum += (n % 10) ** 2
            n = n // 10
        return sum
基本思路

   想要做出这道题,就需要找出背后的规律——循环。如果没有循环,那么平方和每次就不相同,这就很难做了。那我们要怎么证明有循环呢?

  如果平方和永不相同,那么就代表平方和的数值范围无穷大。所以要证明有循环,只需要证明平方和范围有限制即可。假设在计算了k ( k &gt; = 0 k&gt;=0 k>=0) 次平方和后结果为 x k x_k xk,位数为D。如果D == 1,那么 x k + 1 x_{k+1} xk+1最大为 9 2 9^2 92 = 81;如果D == 2,那么 x k + 1 x_{k+1} xk+1最大为 9 2 + 9 2 = 162 9^2 + 9^2 = 162 92+92=162。说这些是为了说明当 d ( x k ) &lt; = 2 d(x_k) &lt;= 2 d(xk)<=2 时( d(x) 表示x的位数 ),其平方和 x k + 1 x_{k+1} xk+1可能会比起 x k x_k xk更大,但最大也就是达到三位数。如果 x k + 1 x_{k+1} xk+1为三位数,那么之后的 x k + 2 x_{k+2} xk+2只会比它小,读者可以自己去尝试一下,当然后面多次迭代之后还可能出现比 x k + 1 x_{k+1} xk+1更大的三位数,但是不管怎么样也不会超过 9 2 ∗ 3 &lt; = 243 9^2 *3 &lt;= 243 923<=243。如果一开始D > 3,也就是初始至少为1000,其值也会慢慢缩小到三位数乃至243以内。这样就说明存在某个循环。

  既然有循环,那么只要经过 k( k >= 0 ) 次计算平方和进入这个循环,就说明这个数不会是快乐数了。怎么判断这个数是不是进入了循环?只要某个数第二次出现,就可以判定了。所以使用Set来存储之前出现过的数字,一旦重复数字出现,则不是快乐数。

复杂度分析

  有人说最多计算六次平方和就可以通过所有测试用例,那么时间复杂度可以看作为 O ( 1 ) O(1) O(1)。空间用到一个set,复杂度为O(m),这里m指的是整个循环的长度,但没有包括未进入循环之前的计算结果长度。

参考资料
Floyd Cycle Detection Algorithm ( C )
int digitSquareSum(int n) {
    int sum = 0, tmp;
    while (n) {
        tmp = n % 10;
        sum += tmp * tmp;
        n /= 10;
    }
    return sum;
}

bool isHappy(int n) {
    int slow, fast;
    slow = fast = n;
    do {
        slow = digitSquareSum(slow);
        fast = digitSquareSum(fast);
        fast = digitSquareSum(fast);
    } while(slow != fast);
    if (slow == 1) return 1;
    else return 0;
}
基本思路

  依然是基于循环的算法,只是发现循环的方法不同。这里slowfast相当于两个指针,在每轮迭代中,slow只计算一次,fast计算了两次,这样当slow到达第二次循环的第一个值时,fast已经到第三次循环的第一个值了。这时候slowfast的值是相等的,就可以判断出循环了。但是如果一个无规律序列里,某个数恰好出现了多次,而且间隔相同,那么这个算法就失效了。

复杂度分析

   时间复杂度为O(1), 空间复杂度也为O(1)

参考资料
  1. Cycle detection
  2. Floyd判圈算法 Floyd Cycle Detection Algorithm
  3. Floyd’s Cycle detection algorithm

除此之外,还有一些纯找数学规律的算法,这里就不介绍了。如有问题,欢迎指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用,题目来源于力扣(LeetCode)的Add Two Numbers问题。根据引用,这是一个关于链表的问题,给定了两个非空的链表,表示两个非负的整。这两个链表的每个节点都存储了一个逆序的字,并且每个节点只能存储一位字。我们需要将这两个相加,并以相同形式返回一个表示和的链表。除了字0以外,这两个不会以0开头。根据引用,这是一道高频题,互联网大厂在笔试和面试中经常会考到这类问题。解决这道题需要基础的据结构与算法知识,并锻炼解题能力。 问题:leetcode相加 回答:这个问题是力扣(LeetCode)上的Add Two Numbers问题,要求计算两个逆序表示的非负整的和,并返回以相同形式表示的链表。它是一道高频题,经常在互联网大厂的笔试和面试中出现。为了解决这个问题,需要使用链表的基本操作,并且要注意进位的处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [LeetCode高频题2:两相加](https://blog.csdn.net/weixin_46838716/article/details/125237688)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [leetcode相加](https://blog.csdn.net/weixin_43199244/article/details/115759341)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值