快乐数
题目链接:202. 快乐数 - 力扣(LeetCode)
编写一个算法来判断一个数n
是不是快乐数。
「快乐数」 定义为:
1. 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
2. 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
3. 如果这个过程 结果为 1,那么这个数就是快乐数。
如果n
是 快乐数 就返回true
;不是,则返回false
。
思路解析:
本题根据所给条件可以推出两种情况:
- 结果为1
- 结果不为1成环
如果将结果为1的看作为环,那么可以将上面两种情况归纳为一种情况:最后的计算结果一定会在环中,如果结果为1,那么环中的所有数值均为1,如果结果不为1,那么环中即为其他数值,如图所示:
通过将题目中对上面的结果进行抽象后,可以发现结果一定会成环,联系到题目:141. 环形链表可以考虑使用双指针算法中的快慢指针解决本题目,具体思路如下:
- 定义一个慢指针
slow
和一个快指针fast
slow
指针走一步,fast
指针走两步- 因为整个过程一定会成环,所以fast和slow指针一定会在环中的某一个位置相遇,判断相遇位置的数值是否为1
本题提问:除了结果为1的另一种结果就是死循环,思考是否存在一种可能结果不是成环导致的死循环,而是无限增大导致的死循环
参考代码:
/** @lc app=leetcode.cn id=202 lang=cpp** [202] 快乐数*/// @lc code=start
class Solution
{
public:int sum_digit(int num){int sum = 0;while (num){int temp = num % 10;sum += temp * temp;num /= 10;}return sum;}bool isHappy(int n){int slow = n;int fast = sum_digit(n);while (slow != fast){slow = sum_digit(slow);fast = sum_digit(sum_digit(fast));}return fast == 1;}
};
// @lc code=end
思考题目解析:
本题中并不会出现因为数值无限增大而导致死循环,即一定会成环,可以使用鸽巢原理进行分析:
鸽巢原理:有n个鸽子巢,有n+1个鸽子,如果将鸽子放入鸽子巢中,那么至少会存在一个鸽子巢中的鸽子数量大于或等于1
参考资料:鸽巢原理
题目中给到的提示数字范围为INT_MAX(32位系统下),假设现在一个有一个远大于INT_MAX的数值,例如9999999999(10个9),此时该数值的和为,即810,那么说明在计算快乐数时,所有的给定数值最后的结果都会出现在[1, 810]这个范围中(鸽子巢),既然如此,根据鸽巢原理,假设数字变化的次数为811(鸽子),因为范围固定,那么最后一个数值肯定会再一次出现在[1, 810]这个范围中,此时就会出现结果循环,所以一定会出现至少一个数值是重复出现导致成环,所以不存在因为数值无限增大而导致死循环