题源: 202. 快乐数
方法:哈希集合检测循环
为了判断一个数字是否最终会陷入循环而不是结束在数字1,我们可以使用哈希集合(在C++中是 unordered_set
)来存储每一步生成的数字。如果我们生成了一个已经在集合中的数字,这意味着我们进入了一个循环,因此该数字不是快乐数。
解题步骤
-
计算数字的平方和:
- 定义一个辅助函数
getSum
来计算给定数字n
的每一位数字的平方和。
- 定义一个辅助函数
-
检测循环:
- 初始化一个空的
unordered_set
来记录出现过的数字。 - 使用一个
while
循环来重复计算平方和直到出现循环或得到数字1:- 计算
n
的平方和。 - 如果平方和为1,那么
n
是快乐数,函数返回true
。 - 如果平方和已经在集合中,说明我们进入了循环,
n
不是快乐数,函数返回false
。 - 否则,将这个平方和加入集合,然后继续循环。
- 计算
- 初始化一个空的
函数分析
getSum
函数通过循环从数字中提取每一位,计算其平方,然后加到sum
上。这是一个高效的方法来持续计算平方和。- 主函数
isHappy
通过持续调用getSum
并使用一个集合检测是否已经计算过当前的平方和来判断n
是否是快乐数。
复杂度分析
- 时间复杂度:O(log n),对于每一位数字平方和的计算过程,虽然不容易直接计算复杂度,但通常认为该过程对于大多数输入是有效的,因为平方和迅速减小。
- 空间复杂度:O(log n),集合中存储的元素数量通常不会超过
n
的位数的平方和,这个数量随n
的大小而增长。
示例
例如,对于 n = 19
:
- 第一步:1^2 + 9^2 = 82
- 第二步:8^2 + 2^2 = 68
- 第三步:6^2 + 8^2 = 100
- 第四步:1^2 + 0^2 + 0^2 = 1
由于最终得到了1,19是一个快乐数。
Code
class Solution {
public:
int getSum(int n){
int sum = 0;
while(n){ //当n不为0时循环,即当n的所有位都平方后就跳出循环了
sum += (n%10) * (n%10); //先将个位平方
n /= 10; //再将十位除成个位
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
while(1){
int sum = getSum(n);
if(sum == 1) return true;
if(set.find(sum) != set.end()) return false;
else set.insert(sum);
n = sum; //如果sum没循环到1也没出现重复数,就继续while循环,将个位依次平方
}
}
};