LeetCode 202 快乐数

1. 题目

202. 快乐数

题目描述

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

快乐数定义:

  1. 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和;

  2. 重复这个过程直到这个数变为 1,则为快乐数;

  3. 如果无限循环但始终变不到 1,则不是快乐数。

示例

输入:n = 19

输出:true

解释:

(1^2 + 9^2 = 82)

(8^2 + 2^2 = 68)

(6^2 + 8^2 = 100)

(1^2 + 0^2 + 0^2 = 1)

输入:n = 2

输出:false,会进入循环 4→16→37→58→89→145→42→20→4

约束

  • (1 <= n <= 2^{31} - 1)

2. 最佳解题思路描述(快慢指针 Floyd 判环,空间 O (1) 最优)

  1. 定义函数 getSum(x):计算数字各位平方和;

  2. 快慢指针:慢指针每次走 1 次平方和,快指针每次走 2 次;

  3. 循环:

    • 若快指针结果 = 1,是快乐数;

    • 若快慢指针相遇,说明出现循环,永远到不了 1,返回 false。

优势

无需哈希集合存历史数字,常数空间;时间效率稳定。

3. 可优化代码(固定循环次数,逻辑有漏洞)

复制代码
class Solution {
public:
    bool isHappy(int n) {
        int res = n;
        for(int i=0;i<10;i++){
            int x = res;
            res = 0;
            while(x){
                res += (x%10)*(x%10);
                x/=10;
            }
            if(res == 1){
                return true;
            }
        }
        return false;
    }
};

代码说明

  1. 表面能通过题目测试用例,但

    存在逻辑漏洞:

    • 强行限制最多循环 10 次,理论上存在某些数字需要超过 10 轮才能到 1,会误判 false;

    • 依靠题目数据范围投机,不具备严谨性,不符合算法标准解法;

  2. 可取部分:while(x) 拆分数字求平方和的逻辑完全正确;

  3. 缺陷:无循环判环机制,依赖固定迭代次数,算法不通用。

4. 两套标准完整代码

版本 1:哈希集合判环(直观易懂)

复制代码
#include <unordered_set>
using namespace std;
class Solution {
public:
    // 计算各位平方和
    int getSum(int x) {
        int sum = 0;
        while (x) {
            int d = x % 10;
            sum += d * d;
            x /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int> seen;
        while (n != 1 && !seen.count(n)) {
            seen.insert(n);
            n = getSum(n);
        }
        return n == 1;
    }
};

版本 2:快慢指针 Floyd 判环(最优 O (1) 空间)

复制代码
class Solution {
public:
    int getSum(int x) {
        int sum = 0;
        while (x) {
            int d = x % 10;
            sum += d * d;
            x /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int slow = n;
        int fast = getSum(n);
        while (fast != 1 && slow != fast) {
            slow = getSum(slow);
            fast = getSum(getSum(fast));
        }
        return fast == 1;
    }
};

5. 总结

  1. 你的代码拆分数字求平方和逻辑正确,但固定循环次数是投机写法,不严谨,不推荐面试使用;

  2. 两种标准正规解法:

    • 哈希集合:记录所有出现过的数字,重复即代表循环;

    • 快慢指针:不用额外存储,空间最优;

  3. 数学结论:所有非快乐数一定会进入循环 4 → 16 → ... → 4,也可每次判断结果是否等于 4 快速返回 false。

6. 相关知识拓展

拓展 1:数学简化写法(利用循环必经过 4)

复制代码
bool isHappy(int n) {
    auto f = [](int x){
        int s=0;
        while(x){int d=x%10;s+=d*d;x/=10;}
        return s;
    };
    while(n != 1 && n !=4) n = f(n);
    return n == 1;
}

拓展 2:复杂度对比

  1. 哈希集合:(O(\log n)) 时间,(O(\log n)) 空间;

  2. 快慢指针:(O(\log n)) 时间,(O(1)) 空间(最优);

  3. 固定 10 次循环:投机写法,无严谨复杂度保障。

拓展 3:易错点复盘

  1. 忘记循环判环,只限定固定迭代次数,存在误判风险;

  2. 拆分数字时丢失个位、平方计算写错;

  3. 快慢指针初始化错误,导致无法进入循环判断。

相关推荐
LuminousCPP13 分钟前
数据结构-二叉树(六):BFS层序遍历与完全二叉树判断|复用链式队列 + (N_0=N_2+1) 性质证明
c语言·数据结构·笔记·算法·二叉树·宽度优先
ZhouDevin1 小时前
算法论文/数据集3——CLD(TMLR2025)压缩训练集,仅保留对验证集有益的样本
人工智能·深度学习·算法·计算机视觉
Tim_101 小时前
【LeetCode】29、两数相除
算法·leetcode·职场和发展
船厂电气自动化ai大模型2 小时前
AI大模型与数学/第63课:矩阵定义、矩阵加法、标量乘法(逐级精讲)
数据结构·人工智能·深度学习·线性代数·算法
余额瞒着我当琳3 小时前
算法修炼 chapter 2 双指针进阶、盛最多水的容器、有效三角形的个数、两数之和、三数之和、四数之和
算法
你压到我腿毛了6663 小时前
C语言冒泡算法(Bubble sort)
c语言·数据结构·算法
靠沿3 小时前
贪心算法专题(三)
算法·贪心算法
super大力张4 小时前
MOE基于结构的药物设计(七):Ligand R-Vectors——如何判断配体可以从哪里继续生长?
数据库·算法·cadd·moe·svl·基于结构的药物设计
Tongsr5 小时前
别只混淆代码:用 Kaleido 加固整个 Android Release AAB
前端·算法·github