[路飞]_每天刷leetcode_45(快乐数 Happy Number)

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

快乐数(Happy Number)

题记

每天刷算法题,快乐吗? 如果你感觉冥思苦想不得其解十分痛苦,多想一想突破之后的感觉,想一想那一刹那的幸福和解题之后通透的快乐,所有的痛苦都是暂时的,一切都会明亮起来。 今天我们一起来解题: 快乐数

LeetCode传送么 202. 快乐数

题目

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

「快乐数」定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果 可以变为  1,那么这个数就是快乐数。 如果 n 是快乐数就返回 true ;不是,则返回 false

Write an algorithm to determine if a number n is happy.

A happy number is a number defined by the following process:

Starting with any positive integer, replace the number by the sum of the squares of its digits. Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy. Return true if n is a happy number, and false if not.

Example 1:

Input: n = 19
Output: true
Explanation:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1



Input: n = 2
Output: false

复制代码

Constraints:

  • 1 <= n <= 231 - 1

思考线


解题思路

这个题, 刚看起来好像很复杂,仔细思考起来却是熟悉的配方熟悉的味道。

判断可能性

首先我们总结推测一波,这道题的结果有多少种可能。

  1. 在寻找快乐的过程中我们始终如一,得到了1,那么这个数就是个快乐数。 例如: 19 -> 82 -> 68 -> 100 -> 1 (找到了1 也就是找到了快乐)
  2. 在寻找快乐的过程中我们陷入了死胡同,一直在重复死亡循环,那么,这个数就不是快乐数。 例如:2 - > 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 - > 4 (在 4 的包围圈内反复循环)
  3. 在寻找快乐的过程中,包袱越来越多,数字越来越大,最后接近无穷大。 这种情况我们不好在脑海中想象。我们要怎么证明这种情况的存在与否呢? 我们既然要找越来越大的数,那么什么样的数字最大呢?肯定是各个位数全是9的数字,那么我们列一个表格来计算一下
Digits Largest next
1 9 81
2 99 162
3 999 243
4 9999 324
5 99999 405
6 999999 485
... ... ...
13 9999999999999 1053

从表格中我们可以清晰的看到,对于3位数的数字,它不可能大于243。这就意味着,要么它在243内循环,出现情况2的结果,要么得到1是个快乐数。而对于4位或4位以上的数字,在计算过程中会快速的下降到3位数的情况。所以我们可以知道,第三种情况不可能存在。我们只要处理第一种和第二种情况即可。

最直观的做法

如果只有上面第 12种可能性的情况下,那么我们如何快速找到结果呢?我们可以使用一个数组arr来保存在计算过程中的值

  • 若最后值变成1,则证明该数字是个快乐数,返回true
  • 若这个值不是1且在数组中出现过,证明进入了循环。不是快乐数,返回 false
  • 若这个值不是1且在数组中没有出现过,把该数组放入数组中,继续执行计算。

根据以上步骤,我们可以很快得到下面的代码

function isHappy(n: number): boolean {
    const arr = [n];
    while(n !==1 ) {
        const find = findHappy(n);
        if(arr.includes(find)) return false;
        arr.push(find);
        n = find
    }

    return true;


};
function findHappy(n: number): number {
    let res = 0;
    while (n > 0) {
        const f = n % 10;
        n = Math.floor(n / 10);
        res += f ** 2
    }
    return res;
}
复制代码

时间复杂度

O(log n)

熟悉的味道

如果只有上面第 12种可能性的情况下,我们定睛一看,这不就和 循环链表的解法相同嘛!,我们可以使用快慢指针来快速判定在寻找快乐的过程中是否进入了循环中,从而得到该数字是否为快乐数。

值得注意的是

  • 我们判断的终止条件是 快指针指向了 1,对应的是循环链表中走向了 null
  • 循环的出现条件仍为,快指针 和慢指针重合了,即为快指针追上的慢指针。

于是我们可以得到如下代码

function isHappy(n: number): boolean {
    if(n === 1) return true;
    let slow = n;
    let fast = findHappy(n);

    while(fast !== 1 && findHappy(fast) !== 1) {
        if(fast === slow) return false;
        fast = findHappy(findHappy(fast))
        slow = findHappy(slow)
    }

    return true;


};
function findHappy(n: number): number {
    let res = 0;
    while (n > 0) {
        const f = n % 10;
        n = Math.floor(n / 10);
        res += f ** 2
    }
    return res;
}
复制代码

时间复杂度

O(logn)

使用数学方法

这种方法是我再网上找的,是会让人直呼哇塞的解法。我们从上面的分析可以得到,如果出现了环,必然是在三位数以内,则必然是小于243的。这样一来我们可以暴力找到所有的环。 而我们会发在243以内只会有一个环,它就是4→16→37→58→89→145→42→20→4。其他所有数字都在进入这个循环的链上,或者在进入1的链上。

于是我们就可以得到一个快速算出结果的算法。

function isHappy(n: number): boolean {
    const cycle = [4, 16, 37, 58, 89, 145, 42, 20];
    while (n !== 1 && !cycle.includes(n)) {
        n = findHappy(n)
    }
    return n === 1

};

function findHappy(n: number): number {
    let res = 0;
    while (n > 0) {
        const f = n % 10;
        n = Math.floor(n / 10);
        res += f ** 2
    }
    return res;
}
复制代码

若观察243以内的数字寻找快乐的规律我们也可以发现,每一个数字寻找快乐的过程总会出现为个位数的情况,而在个位数中只有 17是快乐数。其他都是非快乐数。所以我们也可以根据这个规律来快速判定。

代码如下

function isHappy(n: number): boolean {

    while (n >= 10) {
        n = findHappy(n)
    }
    return n === 1 || n === 7

};

function findHappy(n: number): number {
    let res = 0;
    while (n > 0) {
        const f = n % 10;
        n = Math.floor(n / 10);
        res += f ** 2
    }
    return res;
}
复制代码

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。

Guess you like

Origin juejin.im/post/7054694990865727524