题目链接
题目描述
给定一个正整数,请你判断这个数是不是快乐数。
快乐数的定义:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到该数变为 1,也可能是无限循环但始终变不到 1。如果这个过程最终能够变为 1,那么这个数就是快乐数。
示例 1:
输入: 19
输出: true
解释:
示例 2: 输入: 111 输出: false
解题思路
这道题的核心是判断一个数字经过一系列"各位数字平方和"的变换后,是最终能到达 1,还是会陷入一个无限循环。
1. 变换序列与循环
这个变换过程 n -> next_n
会生成一个数字序列。
- 如果一个数是快乐数,这个序列的终点是 1。
- 如果不是快乐数,序列永远不会到达 1。由于变换后的数值大小有上限(例如,对于任意一个4位数,其各位数字平方和最大为
9^2 * 4 = 324
),所以序列中的数字不会无限增大,最终必然会重复某个已经出现过的数字,从而形成一个环 (Cycle)。
2. 环检测 因此,这个问题就转化为了一个经典的环检测问题。我们只需要判断这个序列是最终汇入 1,还是陷入了其他循环。
最直观的环检测方法是使用哈希集合 (Hash Set)。
- 创建一个哈希集合
seen
,用来存储所有在变换过程中出现过的数字。 - 从给定的数字
n
开始,进入一个循环,反复计算下一个数。 - 在循环的每一步:
- 首先判断当前数字
n
是否等于 1。如果是,则找到了快乐的结局,返回true
。 - 然后判断当前数字
n
是否已经在seen
集合中。如果是,则说明我们进入了一个循环,永远无法到达 1,返回false
。 - 如果以上都不是,说明这是一个新数字,将它加入
seen
集合,然后计算出下一个数,继续循环。
- 首先判断当前数字
为了代码清晰,我们可以将"计算各位数字平方和"的逻辑提取为一个辅助函数。
代码
class Solution {
private:
int getNext(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param n int整型
* @return bool布尔型
*/
bool happynum(int n) {
set<int> seen;
while (n != 1 && seen.find(n) == seen.end()) {
seen.insert(n);
n = getNext(n);
}
return n == 1;
}
};
import java.util.*;
public class Solution {
private int getNext(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param n int整型
* @return bool布尔型
*/
public boolean happynum(int n) {
Set<Integer> seen = new HashSet<>();
while (n != 1 && !seen.contains(n)) {
seen.add(n);
n = getNext(n);
}
return n == 1;
}
}
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param n int整型
# @return bool布尔型
#
class Solution:
def get_next(self, n: int) -> int:
total_sum = 0
while n > 0:
n, digit = divmod(n, 10)
total_sum += digit ** 2
return total_sum
def happynum(self, n: int) -> bool:
# write code here
seen = {n}
while n != 1:
n = self.get_next(n)
if n in seen:
return False
seen.add(n)
return True
算法及复杂度
- 算法: 哈希集合/有序集合(用于环检测)
- 时间复杂度:
- C++:
。变换序列的长度约为
。对于
std::set
,每次插入和查找操作需要时间,其中 K 是集合中的元素数量(最多也为
)。
- Java/Python:
。对于哈希表,每次操作平均时间为
,总时间由变换序列的长度主导。
- C++:
- 空间复杂度:
。空间由集合
seen
使用。其存储的元素数量与时间复杂度的分析类似,也由n
的位数相关。