力扣 202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例:
解析:
这道题主要看第二个条件:重复第一个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
一个快乐数19 -> 82 -> 68 -> 100 -> 1.
对于一个非快乐数他的平方和序列会陷入一个循环4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4。
情况1:这个数循环执行,过程1要么就变变变,变成1。
情况2:这个数不是快乐数,循环执行过程1,变变变,一直变不成1,且进入到一个循环里面,在循环里一直转圈。
我们可以把这两种情况都归类为一种情况。
情况一也是情况2的一种:19 -> 82 -> 68 -> 100 -> 1 -> 1 -> 1 -> 1…。
不过它最后执行循环的都是1。
可以把它抽象想想成如下图所示
我们把循环部分抽象想像成环,之后再只需要判断这个环里的数据是否为1即可,如果不为1,那就是非快乐数。
那么我们首先要判断该结构是否有环状结构。
可以用快慢双指针的思路来解决。
那么解法就是:
- 定义快慢指针
- 慢指针每次向后移动一步,快指针每次走两步。
- 因为快乐数一定会相遇,相遇点肯定就在环形结构中,只需要判断相遇点是否唯一即可。
我们在此题上把双指针的抽象思路具体为把数看成指针:
slow = fast = 2;
slow走一步:
slow执行一次过程1。slow = 2 -> slow = 4;
fast走两步:
fast执行两次过程1。fast = 2 -> fast = 4 -> fast = 16;
补充:
没有条件2这种只有:1和无限循环这样的限制
该题还会有第三种情况:会一直往后走,永远不会重复,不会形成环结构。
但是其实第三种情况是永远不可能出现的。
代码实现:
int bitSum(int n)//返回这个数每一位上的平方和
{
int sum = 0;
while(n)
{
int t = n % 10;
sum += t * t;
n /= 10;
}
return sum;
}
bool isHappy(int n) {
int slow = n, fast = bitSum(n);
while(slow != fast)
{
slow = bitSum(slow);
fast = bitSum( bitSum(fast));
}
//相遇之后只需判断相遇位置的值即可
return slow == 1;
}