快乐数是指对正整数反复计算各位数字平方和,最终结果为1的数;若陷入循环且永不为1,则不是快乐数。判定需检测循环,可用unordered_set记录已出现值或Floyd快慢指针法。

什么是快乐数?先看判定逻辑再写代码
快乐数的定义很明确:对一个正整数反复执行「各位数字平方和」操作,若最终结果为 1,就是快乐数;若进入循环且永远不等于 1,就不是。关键不是算多少次,而是识别是否陷入循环——这点容易被忽略,直接递归或 while 循环不设防会无限跑。
用 unordered_set 记录已出现的和值来检测循环
每次计算出新和值后,先查它是否已在 unordered_set 中。如果是,说明开始循环,返回 false;如果等于 1,立刻返回 true;否则插入集合,继续下一轮。
-
unordered_set查找和插入平均是 O(1),比 vector 或 map 更轻量 - 别用
set(底层红黑树),没必要排序,纯浪费时间 - 初始值要加入集合,比如输入是
2,第一次算得4,但2本身也要记,否则漏判起点重复
示例片段:
int next(int n) {
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
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;
}不用额外空间的 Floyd 判圈法(快慢指针)
把「平方和变换」看作链表,每个数指向它的下一个和值。快乐数最终停在 1(1 的平方和还是 1),非快乐数必然成环。这时可用快慢指针:慢指针走一步,快指针走两步,相遇即环存在。
立即学习“C++免费学习笔记(深入)”;
- 快指针初始必须比慢指针多走一步,否则一开始就相等(如 n=1)会误判
- 函数
next()必须完全一致,不能在快指针里写两次调用而慢指针只一次,否则逻辑错位 - 判断条件是
slow == fast,不是fast == 1—— 等于1是成功退出条件,不是环检测依据
示例关键段:
int slow = n, fast = next(n);
while (fast != 1 && slow != fast) {
slow = next(slow);
fast = next(next(fast));
}
return fast == 1;注意整型溢出和边界情况
int 在多数平台是 32 位,最大值约 21 亿。但快乐数判定中,即使输入是 INT_MAX,其各位平方和最大也不过 9*9*10 = 810(10 位全是 9),所以后续所有中间值都 ≤ 810,完全不会溢出。真正要注意的是:
- 输入为
0不合法(题目限定正整数),但代码里没做校验也没关系,因为题目保证输入有效 -
next(1)返回1,所以单次判断必须先检查是否等于1,否则快慢指针可能卡死 - 不要用递归实现
next(),栈深度不可控,虽然数值小,但习惯上避免无谓递归
实际项目里,如果批量判断大量数,Floyd 法省空间,unordered_set 法更直观易调试;线上服务对内存敏感时,优先选 Floyd。


















