每天学习一点算法 2026/04/07
题目:快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
首先我们要明确,对一个数反复计算各位数字的平方和只有存在两个情况:
- 收敛到
1 - 进入一个固定的循环
假设是一个 m 位的数 ,每一位最大数只能是 9
那最大的计算结果就是 9 * 9 * m = 81m
然而这个数至少是 10 的 m - 1 次方,当 m > 3 时,这个数本身是远远大于它每个位置上的数字的平方和的
所以我们知道一直重复计算一定不是发散的,一旦有了边界那么出现的数就是有限的,所以一直计算一定会进入循环 或者 收敛到 1(1 计算完还是 1 其实也是一种循环)。
于是我们只需要不断的计算直到遇到重复的数 或者 1
typescript
function isHappy(n: number): boolean {
const set = new Set()
function helper(num: number) {
if (set.has(num)) {
return false
}
if (num === 1) {
return true
}
set.add(num)
const next = num.toString().split('').reduce((prev: number, current: string) => {
return prev + Number(current) * Number(current)
}, 0)
return helper(next)
}
return helper(n)
};
既然是判断是否循环,其实我们还可以想到快慢指针的方法(龟兔赛跑),快指针每次计算两次,如果是快乐数快指针一定会先计算到 1,如果不是快乐数两个指针一定会相遇。
typescript
function isHappy(n: number): boolean {
function helper(n: number) {
let totalSum = 0
while (n > 0) {
let d = n % 10
n = Math.floor(n / 10)
totalSum += d * d
}
return totalSum
}
let fast = n, slow = n
fast = helper(fast)
while (fast != slow && fast != 1) {
// 快指针每次计算两次
fast = helper(fast)
fast = helper(fast)
slow = helper(slow)
}
return fast === 1
};
题目来源:力扣(LeetCode)