Leetcode-202 快乐数(最详细讲解)

Algorithm

https://leetcode-cn.com/problems/happy-number/
编写一个算法来判断一个数是不是“快乐数”。

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

示例:

输入: 19
输出: true
解释:
1 2 + 9 2 = 82 1^2 + 9^2 = 82 12+92=82
8 2 + 2 2 = 68 8^2 + 2^2 = 68 82+22=68
6 2 + 8 2 = 100 6^2 + 8^2 = 100 62+82=100
1 2 + 0 2 + 0 2 = 1 1^2 + 0^2 + 0^2 = 1 12+02+02=1

思路1:
这道题定义了一种快乐数,就是说对于某一个正整数,如果对其各个位上的数字分别平方,然后再加起来得到一个新的数字,再进行同样的操作,如果最终结果变成了1,则说明是快乐数,如果一直循环但不是1的话,就不是快乐数,那么现在任意给我们一个正整数,让我们判断这个数是不是快乐数,题目中给的例子19是快乐数,那么我们来看一个不是快乐数的情况,比如数字11有如下的计算过程:

1^2 + 1^2 = 2
2^2 = 4
4^2 = 16
1^2 + 6^2 = 37
3^2 + 7^2 = 58
5^2 + 8^2 = 89
8^2 + 9^2 = 145
1^2 + 4^2 + 5^2 = 42
4^2 + 2^2 = 20
2^2 + 0^2 = 4

我们发现在算到最后时数字4又出现了,那么之后的数字又都会重复之前的顺序,这个循环中不包含1,那么数字11不是一个快乐数,发现了规律后就要考虑怎么用代码来实现,我们可以用 HashSet 来记录所有出现过的数字,然后每出现一个新数字,在 HashSet 中查找看是否存在,若不存在则加入表中,若存在则跳出循环,并且判断此数是否为1,若为1返回true,不为1返回false,代码如下:

class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> st;
        while (n != 1) {
            int sum = 0;
            while (n) {
                sum += (n % 10) * (n % 10);
                n /= 10;
            }
            n = sum;
            if (st.count(n)) break;
            st.insert(n);
        }
        return n == 1;
    }
};

思路二:

这个单链表快慢指针讲很多了,可以直接跳过,去看看算法规模分析吧!

泛化链表结构:如果我们 把链表的节点看成问题中的状态 的话,它可以代表问题中的一个数字、一个阶段等等,是很泛化的东西。而链表的唯一指向关系它又代表什么呢?它其实代表着 状态与状态之间是唯一确定转换 的。也就是说从当前状态是唯一确定转换到下一个状态的。显然快乐数的转换规则完美的符合了这个特性。
在这里插入图片描述

我们根据题目的意思就将 1 作为链表的结尾即 NULL。

那么在单链表中一直走不到空地址意味着什么?就意味着链表有环呗。那么这个快乐数问题就被抽象为链表中是否有环的问题。即,如果这个链表有环那么就不是快乐数,如果链表没环,能指到空地址 1 的话那就说明这个数就是快乐数。

从上面我们得到了解决这个问题的算法思维,但是会不会出现这个链表太长了,有上个几千、几万、几十万的链表单元,影响我们找不到结果呢?我们来考虑一下这个算法的规模。

首先,如果输入值为 int,那么能知道 int 最多也就是一个以 2 开头的 10 位的数字。接着我们来考虑这样一个问题,在 int 数据范围中,哪一个数字 n 它所对应的下一个数字 n 是最大的?

我们能构造得到 1 999 999 999,那么只有构造出 1 个 1 ,9 个 9 的数字在 int 范围内就是最大的,那么下一个节点时多少呢?根据快乐数的定义能得到 9^2 \times9 + 1 = 7309
2
×9+1=730,那么 730 就是在整形范围之内任何一个数字所能映射到的下一个数字都不会超过 730,也就意味着当前所抽象出来的链表结构中节点数目最多不会超过 730 个,如果快指针一次走两步、慢指针一次走一步的话,那么慢指针走的最多,也只不过走了 731\times2 = 1462731×2=1462 步,而快指针就是走了 731731 步。

所以至此就证明完了,在整形快乐数中进行单链表判环的操作的话,操作步骤是有限的,就取个整吧,最多最多也就 2000 步了。所以这个方案是高效可行的。

使用“快慢指针”思想找出循环:“快指针”每次走两步,“慢指针”每次走一步,当二者相等时,即为一个循环周期。此时,判断是不是因为1引起的循环,是的话就是快乐数,否则不是快乐数。
注意:此题不建议用集合记录每次的计算结果来判断是否进入循环,因为这个集合可能大到无法存储;另外,也不建议使用递归,同理,如果递归层次较深,会直接导致调用栈崩溃。不要因为这个题目给出的整数是int型而投机取巧。

就像跑步一样,快乐数跑的是100m冲刺,非快乐数则是在1个400米的环形跑道里无休止的跑下去。
快慢指针就像是专业运动员和业务运动员,在100m的跑道上,两个都会跑到1. 而在环形跑道上,两个指针虽然见面了,但是估计慢指针才跑完一圈,快指针已经跑完两圈了

class Solution {
public:
    bool isHappy(int n) {
        int slow = n, fast = n;
        while(true){
            slow = findNext(slow);
            fast = findNext(fast);
            fast = findNext(fast);
            if(slow == fast)
                break;
        }
        return slow == 1;
        }
    
    int findNext(int n){
        int res = 0;
        while(n>0){
            res += (n%10) * (n%10);
            n /= 10;
    }
    return res;
    }
};
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值