输入:一个整数 n
要求:判断 n 是否为快乐数
-
每次把数字替换成 各位数字的平方和
-
若最终变成
1→ 快乐数 -
若进入 无限循环 → 不是快乐数
输出:true / false
思路:直接模拟 + 用哈希表记录出现过的中间值,用来判断是否进入死循环。
这一题的核心在于快乐数要么true,要么进入死循环,进入死循环的意思就是会重复变成出现过的数字,进而判定为false。
问题就在于为什么进入死循环?
首先,给的n是 1 <= n <= 2^31 - 1,大概是十位左右的数字。无论 n 多大,我们把数字替换成“各位数字的平方和”之后,它会发生强烈的收缩:
-
假设 n 有 k 位,那么下一步最大只会是 81 × k(9² = 81)。
-
即便 n 是 2³¹ - 1 这种十位数,一次迭代后最大也就跌到 81 × 10 = 810。
然后,我们继续看 3 位数的最大平方和:
-
三位数最大的 999
-
平方和 = 81 + 81 + 81 = 243。
因此所有 < 1000 的数,下一步一定 ≤ 243。
而像 243 等值继续平方和,又会迅速跌到几十甚至更小的数字。
这一系列迭代本质上是一个不断“坍缩”的过程。
最终,不论初始 n 是多少,它都会被压缩进一个 非常小的有限集合。
在这个有限集合里迭代:
-
如果最终变成 1 → 快乐数
-
如果长期不能变成 1 → 每步都在有限集合中跳来跳去
-
有限集合 + 无限迭代 → 必定会重复某个数字。
一旦重复,就形成环,也就是我们所说的 死循环。
复杂度:
时间复杂度:O(log n)
空间复杂度:O(log n)
class Solution {
public:
bool isHappy(int n) {
int sum = n;
int tmp;
unordered_map<int, int> root;
while (sum != 1 && root.find(sum) == root.end()) {
root[sum]++;
tmp = sum;
sum = 0;
while (tmp) {
sum += (tmp % 10) * (tmp % 10);
tmp -= tmp % 10;
tmp /= 10;
}
}
return sum == 1;
}
};
5129

被折叠的 条评论
为什么被折叠?



