题目描述
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果 可以变为 1,那么这个数就是快乐数。 如果 n 是快乐数就返回 true ;不是,则返回 false 。
分析
输入:数字 输出:Boolean,表示是否是快乐数
解题方法
这种需要计算的问题,我们需要举几个例子🌰,找到规律。
exp1:
如果 n = 7, 计算的过程是
7 ** 7 = 49
4 ** 4 + 9 ** 9 = 16 + 81 = 97
9 ** 9 + 7 ** 7 = 81 + 49 = 130
3 ** 3 + 1 = 10
=> 最后得到 1
exp2:
如果 n = 116,
9 + 36 = 45
4 ** 4 + 5 ** 5 = 51
5 ** 5 + 1 = 26
2 ** 2 + 6 ** 6 = 40
4 ** 4 = 16
6 ** 6 + 1 = 37
9 + 49 = 58
25 + 64 = 89
64 + 81 = 145
16 + 25 = 51
25 + 1 = 26
4 + 36 = 40
=> 检测到环
那么我们可以假设3种场景:
- 会在一定范围内循环
- 得到 1
- 一直递增*
但是第三种情况并不会出现,我们可以举例子说明:
位数 max (Largest Next)
1 9 81
2 99 162
3 999 243
4 9999 324
5 99999 405
6 999999 567
7 9999999 567
8 99999999 729
9 999999999 810
10 9999999999 891
11 99999999999 972
12 999999999999 1053
13 9999999999999 1134
14 99999999999999 1215
可以看到,不论位数有多大,在计算过程中,计算出一定大的值之后,都会变小,然后直到得到1,或者在某个区间循环。
我们可以根据这点,用 code 检测这个计算的过程会得到1还是一个环。
代码
/**
* @param {number} n
* @return {boolean}
*/
var isHappy = function (n) {
// 用快慢指针的方法,检测计算过程是否会出现重复的值,也就是是否会有环的出现
let slow = n,
fast = n;
// 只要没得到 fast === 1 && 没检测到环,就一直进行计算过程
while (fast !== 1) {
slow = _next(slow);
fast = _next(_next(fast));
if (fast === slow) break;
}
// 用一个函数来执行计算的过程,每一位进行平方加到结果去,最后返回这个结果
function _next(num) {
let ret = 0;
while (num) {
ret += Math.pow(num % 10, 2);
num = Math.floor(num / 10);
}
return ret;
}
// 计算过程结束后,看得到的结果是不是1
return fast === 1;
};