快乐数是指一个正整数通过反复计算各位数字平方和最终得到1;若进入循环而无法到达1则不是快乐数。关键在于过程必落入有限范围(≤243),故可用哈希集检测重复值判环,或用快慢指针法以o(1)空间检测环。

什么是快乐数,以及为什么不能只算一次平方和
一个正整数是快乐数,当且仅当它通过反复将各位数字的平方和替换自身,最终结果变为 1;如果进入循环却始终不出现 1,就不是快乐数。关键点在于:**过程可能无限循环,但不会发散到无穷大**——因为对于任意 ≤ 999 的数,其各位平方和最大为 9²×3 = 243,更大的数也会快速掉进这个范围。所以只要检测是否重复出现某个中间值,就能判断是否死循环。
用 unordered_set 检测循环是最直接的做法
每次计算新值后存入 std::unordered_set<int></int>,若发现已存在,说明进入环,返回 false;若遇到 1,返回 true。这是最贴近定义、不易出错的实现方式。
常见错误包括:
– 忘记清空或复用 set 导致多组调用出错
– 把 1 判定放在循环末尾,导致首次输入就是 1 时跳过判断
– 用 vector 或线性查找代替哈希表,徒增 O(n) 开销
- 每次迭代前先检查当前值是否为
1,是则立即返回true - 计算平方和时用
n % 10和n / 10安全取位,避免字符串转换开销 - set 生命周期应限于单次判定函数内,不要静态或全局复用
bool isHappy(int n) {
std::unordered_set<int> seen;
while (n != 1 && seen.find(n) == seen.end()) {
seen.insert(n);
int next = 0;
while (n) {
next += (n % 10) * (n % 10);
n /= 10;
}
n = next;
}
return n == 1;
}</int>
快慢指针法(Floyd Cycle Detection)适合内存受限场景
既然所有轨迹最终必成环或抵达 1,就可以把过程看作链表找环问题:用两个变量,slow 走一步、fast 走两步(即算两次平方和)。若二者相遇且不等于 1,说明有环;若某次 slow == 1 或 fast == 1,就是快乐数。
优势是 O(1) 空间;缺点是逻辑稍绕,容易写错步数顺序。尤其注意:
– 必须先更新 slow,再更新 fast 两次,否则初值相同会立刻退出
– fast 更新时要防 1 提前终止:若第一次更新后已是 1,第二次就不该再算
- 初始化
slow = n,fast = getNext(getNext(n))更稳妥 - 循环条件用
slow != fast,而非fast != 1 && slow != 1,否则漏判 - 退出循环后,只需检查
slow == 1即可,不用再管fast
get_next() 函数必须独立封装并正确处理个位数
无论用哪种主逻辑,提取各位平方和的辅助函数 getNext 都要健壮。典型坑点:
– 输入为 0 时返回 0(虽然题目限定正整数,但中间值可能出现 0)
– 用 while (n > 0) 而非 while (n),避免负数干扰(虽本题无负数,但习惯要好)
– 不要用 std::to_string,字符串构造+遍历比纯数值运算慢 3–5 倍
这个函数看似简单,但线上题库中因它写错导致 WA 的比例很高,尤其是忘记对 0 特判或循环条件松动。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











