JS判断整数快乐数

1,414 阅读3分钟

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为  1,那么这个数就是快乐数。
如果 n 是快乐数就返回 true ;不是,则返回 false
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:
输入:n = 2
输出:false

我以为快乐数看到他它就会快乐。

解析:

根据快乐树的定义,快乐树是将正整数的每一位(个十百千万...等等位)平方再相加的和组成一个新的数,然后再一次做同样的操作,直到这个数变为1。我们可以假设,如果这个数不是快乐数,那么这样的操作会一直进行下去,无限循环!所以可以得知:

  • 判断快乐树的底层逻辑和标准是以上操作是否是无限的,还是最终会得到1这个数。
  • 既然无限,那必有相交。也就是说同样的数会出现至少2次,导致流程重复,才出现了无限循环。

总结: 判断是否为快乐数,即判断平方和操作会有交点或得到1

分解:

首先写一个获取整数每一位数的平方和算法:

const getNumber = (n) => {
    let res = 0
    do {  
        const a = n % 10
        n = (n - a) / 10
        res += a * a
    } while( n >= 10)
    res += n * n
    return res
}

PS:也曾尝试过将整数转换为字符串数组,然后分别对每个元素取得平方再相加,但性能方面比整数计算要低一些。

如何判断交点以及每次计算结果是否为1呢?

可以将每一次的计算结果和1做比对,如果为1,那么就是快乐数,eturn true.如果不为1,那么将该数存在一个数组里面,并且继续进行 getNumber() 的操作。每一次操作后都会和1比对并且查看数组里面是否存在过该数,如果存在那么表示有相交,return false

/**
 * @param {number} n
 * @return {boolean}
 */

const getNumber = (n) => {
    let res = 0
    do {  
        const a = n % 10
        n = (n - a) / 10
        res += a * a
    } while( n >= 10)
    res += n * n
    return res
}

var isHappy = function(n) {
    let list = []
    while(true) {
      n = getNumber(n)
      if (n === 1) {
          return true
      } else if (list.indexOf(n) !== -1) {
         return false
      }
      list.push(n)
    }
};

以上可以完成对快乐数的判断.

image.png

那么如果我不想开辟新的数组去解决这个问题呢??

如果想要判断某个链是否循环,也可以考虑使用双指针龟兔赛跑算法去解决。这里不做过多介绍,可以参阅之前文章 双指针龟兔赛跑判断链表是否成环

龟兔赛跑算法:

/**
 * @param {number} n
 * @return {boolean}
 */

const getNumber = (n) => {
    let res = 0
    do {  
        const a = n % 10
        n = (n - a) / 10
        res += a * a
    } while( n >= 10)
    res += n * n
    return res
}

var isHappy = function(n) {
    let slow = getNumber(n)
    let quick = getNumber(getNumber(n))
    if (quick === 1) {
        return true
    }
    while(slow !== quick) {
        slow = getNumber(slow)
        quick = getNumber(getNumber(quick))
        console.log({quick})
        if (quick === 1) {
            return true
        }
    }
    return false
};