快乐数是反复计算各位数字平方和最终得1的正整数;不能仅靠固定轮数判断,因循环起点未知,须用哈希表检测重复或快慢指针判环,遇4返回false仅为经验规律,不可靠。

什么是快乐数,以及为什么不能用简单循环判断
快乐数的定义是:对一个正整数反复计算其各位数字的平方和,最终结果为 1,则它是快乐数;如果进入循环且永远不等于 1(比如陷入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 这个环),就不是快乐数。关键点在于——你无法靠“跑够多少轮就停”来判断,因为循环起点不确定,必须检测重复状态。
用 unordered_set 记录已出现的平方和
最直观的做法是把每次算出的平方和存进 std::unordered_set,一旦发现重复,说明进入死循环,直接返回 false;若某次得到 1,返回 true。
实操注意点:
- 每次迭代前先检查当前值是否为 1,是则立刻返回 true
- 每次计算平方和后,先查
seen.find(sum) != seen.end(),再决定是否插入,避免漏判刚生成的重复值 - 不要用
set(红黑树),它带 log 开销;unordered_set平均 O(1),更合适 - 输入保证是正整数,无需处理 0 或负数
示例核心逻辑:
int next(int n) {
int sum = 0;
while (n) {
int d = n % 10;
sum += d * d;
n /= 10;
}
return sum;
}
<p>bool isHappy(int n) {
unordered_set<int> seen;
while (n != 1 && seen.find(n) == seen.end()) {
seen.insert(n);
n = next(n);
}
return n == 1;
}</int></p>
用快慢指针替代哈希表节省空间
快乐数的平方和变换本质上是一个链表(每个数指向它的下一个平方和),而“是否成环”正是 Floyd 判圈算法的经典场景。用快慢指针能将空间复杂度从 O(k) 降到 O(1),k 是环前路径长度加环长。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
使用条件与细节:
- 快指针每次走两步(
slow = next(slow); fast = next(next(fast));),慢指针走一步 - 循环条件是
slow != fast,退出时若slow == 1才算快乐数(不能只看是否相遇) - 必须在每次移动后检查是否到达 1,否则可能错过终止点
- 初始时快慢指针都从
n开始,不是n和next(n),否则会漏掉 n==1 的情况
为什么 4 是常见非快乐数的标志
所有非快乐数最终都会落入以 4 为起点的固定循环,这是数学上已被证明的性质(所有小于 1000 的非快乐数都会在几步内到达 4)。所以有人用“遇到 4 就返回 false”来简化判断——但这只是经验规律,不是通用解法。
不推荐依赖这个技巧的原因:
- 它没被标准库或题目约束保证,属于隐含假设
- 虽然实际测试中几乎不会出错,但代码可读性和可维护性差
- 一旦题目扩展到其他进制或自定义变换规则,该规律立即失效
真正可靠的判断依据只有两个:到达 1,或检测到重复状态(无论重复的是 4 还是别的数)。
边界情况容易忽略:isHappy(1) 必须返回 true,isHappy(10) 也 true(1²+0²=1),但 isHappy(2) 要走完整环才能确认 false——别在中间某轮手动 break。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










