对于一个数n一直进行取位置上的数字进行平方和的计算,会有三种情况
1、最终计算结果为1
2、计算出的某一结果为之前已经计算的结果,即出现了循环圈
3、出现无限不循环的情况
对于第三种情况
当n为三位数时,计算出的平方和不大于243
当n为四位数时,最大平方和为324 < 999,再一步计算出的平方和小于243
当n为四位数即以上位数时,计算出的平方和位数远小于数n,也就是取值被大大缩小。例如十三位数的n下一步的最大平方和1053 < 9999,再下一步的平方和小于324 < 999,再下一步的平方和小于243
于是我们可得,数字n进行不断取值平方和的计算,可能会在243下的所有数字内循环或是最终结果为1,不可能存在无限不循环的情况
因此,题目就变为了判断是否出现了循环圈,有两种方法
1、用HashSet存放每个出现过的n,判断是否重复
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class HappyNum {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
int n = scanner.nextInt();
HappyNum h = new HappyNum();
System.out.println(h.isHappy1(n));
}
}
public int caculate(int n) { //计算下一步的平方和
int num = 0;
while (n != 0) {
num += (n % 10) * (n % 10);
n /= 10;
}
return num;
}
//用HashSet存放每个出现过的n,判断是否重复
public boolean isHappy1(int n) {
Set<Integer> set = new HashSet<>(); //存放每个出现过的n
while (n != 1) {
if (set.contains(n)) { //如果n曾经出现过,说明会出现循环,返回false
return false;
} else { //如果n未曾出现过,则加入set
set.add(n);
}
n = caculate(n); //把n更新为每一位的平方和
}
return true;
}
}
2、快慢指针法
由于只存在两种情况,存在最终结果为1的链表为单向线性的,快跑者的“速度”大于慢跑者,那么快跑者一定先到达1 ;如果最终结果为循环,那么一定在某个时间,快跑者会倒追慢跑者一圈,二者相遇
注意点:快指针每次跳两个不用担心跳过1的点,因为1的点的下一个点还是1
快指针在慢指针后一个位置出发,这是因为只要求可追击,不要求环形列表的起始点。
public boolean isHappy2(int n) {
int fast = n, slow = n;
//这里设定二者从同一起点出发,但实际上只需要保证快跑者的起点在慢跑者的起点之后即可
while(fast != 1 && slow != 1){
fast = caculate(caculate(fast)); //快指针计算两次平方和
slow = caculate(slow); //慢指针计算一次平方和
if(fast == slow && fast != 1){ //二者相遇并且快跑者的点位不为1
return false;
}
}
return true;
}
[数学规律] 202. 快乐数(寻找数学规律、判断是否无限循环:Set、快慢指针法)_m0_38142029的博客-CSDN博客_快乐数怎么找
https://leetcode.cn/problems/happy-number/solutions/224894/kuai-le-shu-by-leetcode-solution/