题目:202. 快乐数
解法一:快慢指针
题目中提到在计算快乐数时,会出现无限循环的情况,因此遍历时需要判断是否存在循环,若存在循环则跳出循环。而各个位数相加为1也是一个循环,因为12=1,会持续循环下去,那么当我们跳出循环时,判断循环的原因是否由1引起,若是如此,该数即为快乐数。
class Solution {
public boolean isHappy(int n) {
int slow = n, fast = n;
do {
slow = getNext(slow);
fast = getNext(fast);
fast = getNext(fast);
} while (slow != fast);
return slow == 1;
}
public int getNext(int n) {
int bit, res = 0;
while (n != 0) {
bit = n % 10;
res += bit * bit;
n /= 10;
}
return res;
}
}
注意点:
- 整型最大13位,当每位都为9时,各位的平方和最大为1053,而再求下一个平方和时,一定不会超过1053,所以,若有循环,则一定会在该范围出现,而不会出现计算出无穷大的情况
- 当需要判断是否出现循环时,可以使用快慢指针算法
- 判断是否为快乐数,只需判断循环的原因是否由1引起
- 在进入循环后,快慢指针会出现3种情况
- fast在后,slow在前,相距1格,下次相遇。
- fast在后,slow在前,相距2格,下一次移动,变为相距1格。
- 其它时刻,每次环内移动,距离缩短1,直至相距2格。
ptr
和slow
相遇位置一定在入环点
快慢指针参考:深入理解快慢指针算法 – 链表环路检测 - 知乎 (zhihu.com)
解法二:哈希表检测循环
将每次遍历到的数字存在hash表中,当存入数字和已有数字重复时,判断存在循环,判断循环元素是否为1,为1则代表该数为快乐数
class Solution {
private int getNext(int n) {
int totalSum = 0;
while (n > 0) {
int d = n % 10;
n = n / 10;
totalSum += d * d;
}
return totalSum;
}
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;
}
}
注意:第一个重复的元素即为入环点,看上图理解