问题描述:
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
例如:
那么如何去判断一个数是否是快乐数呢
由于快乐数最后变形后是1,那么给定一个数,他经过快乐数的判断步骤的类型有三种:
1.确实经过判断,最终返回1
2.经过不断的平方相加,发现进入了死循环:
3.经过不断的平方相加操作,发现数据无穷大;
然而第三种情况并不存在,因为若数据为13位的9(9999999999999),然而经过平方相加之后为9*9*13=1053,相当于从13位数变为4位数,所以经过平方相加,并不会使使得数据出现趋于无穷大的情况;
无论使用哈希表还是快慢指针,首先都需要一个方法,将数据的每一位分开进行平方相加:
private int getNext(int n) {
int sum = 0;
while(n>0){
int a=n%10; //取个位
int b=n/10; //将个位去除
sum=sum+a*a; //累加平方和
}
}
return sum;
}
使用哈希表解决:
新建一个哈希表,将每次经过平方相加操作的数据存储到哈希表中,并放入循环之中,判断条件即为:当数据不为1或者此数据在哈希表中不存在(若存在说明死循环已开始);
如果数据因为运算之后等于1 ,那么和return的n==1便相同,所以返回true;
如果数据因为已经在哈希表中存在而退出循环,那么此时的n的值肯定和1不同,所以返回false:
public boolean isHappy(int n) {
Set<Integer> seen = new HashSet<>();
while (n != 1 && !seen.contains(n)) {
seen.add(n);
n = getNext(n);
}
return n == 1; //与1进行比较,若相同则返回true,若不同则返回false
}
使用快慢指针:
因为看到了循环链表的存在,所以可以使用快慢指针,此题由于有getNext方法所以不用创建链表;
首先定义,快指针和慢指针(在快慢指针循环移动位置时,要对快慢指针所指向的节点进行判断是否相等,所以初始化指针的时候不能将这两个指针定义相同):
int slowRunner = n;
int fastRunner = getNext(n);
然后进入循环体,让慢指针每循环一次移动一位,快指针每循环一次移动两位;循环条件便是慢指针和快指针指向的是不同的元素,或者其中一个指针指向的不是1
while (fastRunner != 1 && slowRunner != fastRunner) {
slowRunner = getNext(slowRunner);
fastRunner = getNext(getNext(fastRunner));
}
return n==1;
如果某一个指针指向1,那么久跳出循环,与return的值比较,发现相等,那么就返回true;
如果两个指针指向同一个元素,那么说明要进入死循环,则跳出循环,与返回的1进行比较,肯定不是1,所以返回false;