题目地址:
https://leetcode.com/problems/happy-number/
对一个int作如下操作,将其十进制每一位求平方和,不断重复,如果能在有限步到 1 1 1,就返回true,否则返回false。
可以用一个哈希表存储每一步操作后得到的数,如果某次操作没有得到 1 1 1,但得到了之前得到过的数,那就返回false;若得到了新数,则加入哈希表;否则如果得到了 1 1 1,就返回true。代码如下:
import java.util.HashSet;
import java.util.Set;
public class Solution {
public boolean isHappy(int n) {
// 将存储当前得到的数的变量初始化为n
int cur = n;
// set记录每次操作得到的数
Set<Integer> set = new HashSet<>();
// 如果得到的数不是1,则尝试加入set;若加入失败,说明有重复,返回false,否则继续重复操作
while ((cur = squareSum(cur)) != 1) {
if (!set.add(cur)) {
return false;
}
}
return true;
}
private int squareSum(int n) {
int sum = 0;
while (n != 0) {
int a = n % 10;
sum += a * a;
n /= 10;
}
return sum;
}
}
时间复杂度 O ( log 2 n ) O(\log^2 n) O(log2n),空间 O ( log n ) O(\log n) O(logn)。
也可以用链表求环的方法做。设 x → f ( x ) → f 2 ( x ) → . . . x\to f(x)\to f^2(x)\to ... x→f(x)→f2(x)→...,那么由于 f ( x ) ≤ 9 2 ( log 10 x + 1 ) f(x)\le 9^2(\log_{10}x+1) f(x)≤92(log10x+1),所以必然存在重复数字,从而存在环。即判断环是否是 1 1 1。C++:
class Solution {
public:
bool isHappy(int n) {
int slow = n, fast = n;
do {
slow = calc(slow);
fast = calc(calc(fast));
} while (fast != slow);
return fast == 1;
}
int calc(int n) {
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
};
时间复杂度一样,空间 O ( 1 ) O(1) O(1)。