202. 快乐数

159 阅读2分钟

题目描述

编写一个算法来判断一个数 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. 会在一定范围内循环
  2. 得到 1
  3. 一直递增*

但是第三种情况并不会出现,我们可以举例子说明:

  位数    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;
};