题目来源:LeetCode202:快乐数
问题抽象:判断一个正整数是否为快乐数(通过重复计算各位平方和最终得到 1),需满足以下核心需求:
-
快乐数判定规则:
- 初始正整数
n,迭代计算:n = ∑(每位数字的平方); - 若迭代最终收敛到
1→ 是快乐数; - 若迭代进入无限循环(不含
1)→ 非快乐数。
- 初始正整数
-
循环检测策略:
- 哈希集记录历史值:存储每次迭代结果,若出现重复值则判定循环(非
1); - 快慢指针法(空间优化):
slow计算一次迭代,fast计算两次迭代;- 若
slow == fast且结果非1则判定循环。
- 哈希集记录历史值:存储每次迭代结果,若出现重复值则判定循环(非
-
迭代终止条件:
- 结果为
1→ 返回true; - 检测到循环 → 返回
false; - 数学性质:循环必含
4→16→37→58→89→145→42→20→4(非快乐数公共环)。
- 结果为
-
边界处理:
- 输入
n为正整数(1 ≤ n ≤ 2^31-1); n=1时直接返回true;- 大数优化:迭代过程数值快速衰减(如
999→243),无需担心溢出。
- 输入
输入:正整数 n
输出:布尔值 true/false(表示是否为快乐数)
解题思路
要判断一个数是否是快乐数,关键在于检测计算过程中是否会出现循环。解题思路如下:
- 问题分析:快乐数的计算过程是不断将数字替换为各位数字的平方和。若最终能得到 1,则是快乐数;否则会进入不包含 1 的循环。
- 循环检测:使用快慢指针法(Floyd Cycle Detection)检测循环:
- 慢指针:每次计算一次平方和。
- 快指针:每次计算两次平方和。
- 如果快指针变为 1,说明是快乐数。
- 如果快慢指针相遇(值相等)且不为 1,说明进入循环,不是快乐数。
- 优化点:
- 空间优化:快慢指针法只需常数空间,避免使用 HashSet 存储中间结果。
- 时间优化:平方和计算高效,且快指针能快速检测到循环或 1。
- 辅助函数:
getNext函数计算数字的平方和。
代码实现(Java版)🔥点击下载源码
class Solution {
public boolean isHappy(int n) {
int slow = n; // 慢指针初始化为 n
int fast = getNext(n); // 快指针初始化为 n 的下一个数(一次平方和)
// 当快指针不为1且快慢指针不相等时继续循环
while (fast != 1 && slow != fast) {
slow = getNext(slow); // 慢指针移动一步
fast = getNext(getNext(fast)); // 快指针移动两步
}
// 若快指针为1,则是快乐数;否则进入循环,不是快乐数
return fast == 1;
}
// 辅助函数:计算数字 n 的各位平方和
private int getNext(int n) {
int sum = 0;
while (n != 0) {
int digit = n % 10; // 取最后一位数字
sum += digit * digit; // 累加平方
n /= 10; // 移除最后一位
}
return sum;
}
}
代码说明
- 快慢指针机制:
- 慢指针 (slow):每次调用一次
getNext,模拟单步计算。 - 快指针 (fast):每次调用两次
getNext,模拟双步计算。 - 终止条件:
- 若
fast == 1,说明到达快乐数终点,返回true。 - 若
slow == fast且不为 1,说明进入循环,返回false。
- 若
- 慢指针 (slow):每次调用一次
- 辅助函数
getNext:- 通过取模 (
% 10) 和整除 (/ 10) 逐位计算平方和。 - 时间复杂度:O(log n),其中 log n 是数字的位数。
- 通过取模 (
- 整体复杂度:
- 时间复杂度:O(log n),平方和计算迅速收敛,快慢指针高效检测循环。
- 空间复杂度:O(1),仅使用常数额外空间。
提交详情(执行用时、内存消耗)

1140

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



