题目描述
题目链接:202.快乐数
编写一个算法来判断一个数n
是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和
。
然后重复这个过程直到这个数变为 1
,也可能是无限循环
但始终变不到 1
。
如果这个过程 结果为 1
,那么这个数就是快乐数。
如果n
是快乐数
就返回true
;不是,则返回false
。
示例 1
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2
输入:n = 2
输出:false
提示
- 1 <=
n
<= 231 - 1
解题核心
循环链表问题,无论输入什么数,它的结果不是1就是在无限循环
Digits | Largest | Next |
---|---|---|
1 | 9 | 81 |
2 | 99 | 162 |
3 | 999 | 243 |
4 | 9999 | 324 |
13 | 9999999999999 | 1053 |
对于3位数的数字
,它不可能大于243
。这意味着它要么被困在243
以下的循环内,要么跌到1
。4位或4位以上的数字
在每一步都会丢失一位,直到降到3位为止。所以我们知道,最坏的情况下,算法可能会在 243
以下的所有数字上循环,然后回到它已经到过的一个循环或者回到1
,但它不会无限期地进行下去,所以我们排除第三种选择。
解法一:快慢指针
当快指针指向的结果为1或者被慢指针追上的时候可以结束操作,相当于把问题转换成链表是否有环
public boolean isHappy(int n) {
int slow = n;
int fast = SquaresSum(n);
while (fast != 1 && slow != fast) {
slow = SquaresSum(slow);//慢指针走一步
fast = SquaresSum(SquaresSum(fast));//快指针走两步,1的平方和还是1,不影响
}
return fast == 1;
}
public int SquaresSum(int num) {
int sum = 0;
while (num > 0) {
sum += (num % 10) * (num % 10);
num /= 10;
}
return sum;
}
解法二:数学逻辑
显然题目的无限循环是在一个圈内循环,可以发现10以内只有1和7为快乐数,而循环无论如何都会进入到10以内
public boolean isHappy1(int n) {//能凑到10^n就是快乐数,10以内只有1和7为快乐数
while (true) {
if (SquaresSum(n) != 1) {
n = SquaresSum(n);
} else {
return true;
}
if (n < 10 && n > 1 && n != 7) {
return false;
}
}
}
public int SquaresSum(int num) {
int sum = 0;
while (num > 0) {
sum += (num % 10) * (num % 10);
num /= 10;
}
return sum;
}
我们去推导可以发现,这个循环会存在规律4->16->37->58->89->145->42->20->4
,只要进入到这个循环就一定不是快乐数
public boolean isHappy3(int n) {
Set<Integer> cycleMembers = new HashSet<>(Arrays.asList(4, 16, 37, 58, 89, 145, 42, 20));
while (n != 1 && !cycleMembers.contains(n)) {
n = SquaresSum(n);
}
return n == 1;
}
public int SquaresSum(int num) {
int sum = 0;
while (num > 0) {
sum += (num % 10) * (num % 10);
num /= 10;
}
return sum;
}