快乐数是指正整数经反复计算各位数字平方和最终得1的数;判断逻辑需检测循环,可用哈希表记录已出现和或快慢指针法,核心是识别是否陷入非1循环而非依赖迭代上限。

什么是快乐数,以及判断逻辑怎么写
快乐数的定义是:对一个正整数反复计算其各位数字的平方和,最终结果为 1,则它是快乐数;如果进入循环且永远不出现 1,就不是快乐数。关键在于识别「循环」——不能靠猜次数上限,得用实际检测重复值的方式。
最直接的做法是用 std::unordered_set 记录已出现过的和。每次算出新和后,先查是否已存在:存在说明循环,返回 false;等于 1 则返回 true。
- 不要用固定迭代次数(比如 100 次)来“保险”,某些非快乐数可能在第 101 次才显现出循环
-
get_next_number()函数要小心处理个位为 0 的情况,但其实取模和整除本身就能自然跳过,无需特判 - 输入保证是正整数,不用检查
如何高效提取各位数字并求平方和
常见错误是把数字转成字符串再遍历,虽可行但有额外内存和类型转换开销。更推荐纯数值法,用 % 10 和 / 10 循环拆解:
int get_next_number(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
-
n % 10取当前末位,n /= 10去掉末位,比字符串to_string+for循环更快也更符合 C++ 习惯 - 注意
digit * digit不要用pow(digit, 2),后者是浮点运算,慢且可能有精度隐患 - 即使
n是个位数(如 7),循环仍能正确执行一次,结果是 49,没问题
用快慢指针代替哈希表是否可行
可以,而且空间复杂度从 O(n) 降到 O(1)。因为「各位平方和」映射本质是一个确定性函数,所有起始值最终都会进入环或抵达 1——这正好符合链表判环场景,适合用 Floyd 判圈算法。
- 快指针每次走两步(即算两次
get_next_number),慢指针走一步 - 若相遇时值为 1,说明已到终点;否则说明陷入非 1 的环,不是快乐数
- 注意初始化:慢指针从原数开始,快指针必须从
get_next_number(n)开始,否则第一次就相等(都等于 n) - 这个方法省空间,但代码稍长,调试时不如哈希表直观;竞赛中常用,工程中哈希表更易维护
容易被忽略的边界与性能细节
真正上线或跑大量数据时,几个点常被跳过:
-
int足够存中间和:最大可能是 999999999 → 9×9×9 = 729,远小于INT_MAX,不会溢出 - 用
std::unordered_set时,建议预留容量:seen.reserve(30),因为实际路径长度极少超过 20 步 - 如果批量判断多个数,别在循环里反复构造
unordered_set,可复用或改用局部静态对象(视线程安全需求而定) - Clang/GCC 下,开启
-O2后get_next_number很容易被内联,不必手动加inline
快乐数判断本身不难,难点在意识到「循环检测」是核心,而不是「算到 1」——漏掉这点,要么无限循环,要么靠玄学设上限硬扛。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











