LeetCode 202. 快乐数(C语言详解 | 三种解法 | 哈希表 + 快慢指针)

一、题目描述

题目链接:
https://leetcode.cn/problems/happy-number/

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

快乐数定义:

对于一个正整数:

  1. 每一次将该数替换为 各位数字的平方和

  2. 然后重复这个过程

  3. 直到结果变为 1

  4. 或者 进入无限循环

如果最终结果为 1,则该数为 快乐数。


示例 1

复制代码
输入:n = 19
输出:true

过程:

复制代码
1² + 9² = 82
8² + 2² = 68
6² + 8² = 100
1² + 0² + 0² = 1

最终得到 1,所以 19 是快乐数。


示例 2

复制代码
输入:n = 2
输出:false

提示

复制代码
1 <= n <= 2^31 - 1

二、题目核心思想

本题核心操作:

复制代码
不断计算:
各位数字平方和

例如:

复制代码
19
↓
1² + 9² = 82
↓
8² + 2² = 68
↓
6² + 8² = 100
↓
1² + 0² + 0² = 1

如果:

复制代码
最终 == 1 → 快乐数
进入循环 → 不是快乐数

因此问题本质就是:

如何检测是否进入循环


三、辅助函数:计算平方和

无论哪种解法,都需要一个函数计算:

复制代码
各位数字平方和

int getNext(int n)
{
    int sum = 0;

    while (n)
    {
        int digit = n % 10;
        sum += digit * digit;
        n /= 10;
    }

    return sum;
}

四、解法一:暴力循环(基础版)

思路

不断计算平方和:

复制代码
n → next → next → next ...

如果:

复制代码
n == 1

说明是快乐数。

但这种写法 无法判断循环,不推荐。


五、解法二:哈希表判重

思路

如果一个数不是快乐数,一定会 进入循环。

例如:

复制代码
2
↓
4
↓
16
↓
37
↓
58
↓
89
↓
145
↓
42
↓
20
↓
4   (出现重复)

因此我们可以:

复制代码
用哈希表记录出现过的数字

如果:

复制代码
再次出现 → 说明进入循环

算法步骤

复制代码
1 初始化哈希表
2 不断计算平方和
3 如果出现1 → 返回true
4 如果出现重复 → 返回false

C语言实现

复制代码
#include <stdbool.h>

int getNext(int n)
{
    int sum = 0;

    while (n)
    {
        int digit = n % 10;
        sum += digit * digit;
        n /= 10;
    }

    return sum;
}

bool isHappy(int n)
{
    int seen[1000] = {0};

    while (n != 1 && !seen[n])
    {
        seen[n] = 1;
        n = getNext(n);
    }

    return n == 1;
}

复杂度分析

复制代码
时间复杂度:O(log n)
空间复杂度:O(n)

六、解法三:快慢指针(最优解)

这是 面试最推荐的写法。

思想来源:

复制代码
Floyd 判环算法

类似:

复制代码
判断链表是否有环

思路

定义:

复制代码
slow 每次走一步
fast 每次走两步

如果:

复制代码
fast == 1

说明是快乐数。

如果:

复制代码
slow == fast

说明进入循环。


图解

复制代码
slow :  n → next → next
fast :  n → next → next → next → next

若存在循环:

复制代码
slow == fast

C语言实现

复制代码
#include <stdbool.h>

int getNext(int n)
{
    int sum = 0;

    while (n)
    {
        int digit = n % 10;
        sum += digit * digit;
        n /= 10;
    }

    return sum;
}

bool isHappy(int n)
{
    int slow = n;
    int fast = getNext(n);

    while (fast != 1 && slow != fast)
    {
        slow = getNext(slow);
        fast = getNext(getNext(fast));
    }

    return fast == 1;
}

复杂度分析

复制代码
时间复杂度:O(log n)
空间复杂度:O(1)

优于哈希表方法。


七、为什么一定会进入循环?

数学证明表明:

任何数字经过若干次计算后:

复制代码
最终都会落到 1000 以内

如果不是快乐数,会进入固定循环:

复制代码
4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4

因此:

复制代码
出现4基本可以判断不是快乐数

有些代码会直接判断 n != 4。


八、面试总结

本题本质是:

复制代码
循环检测问题

常见解法:

解法 思想 空间
暴力循环 不推荐 -
哈希表 判重 O(n)
快慢指针 Floyd判环 O(1)

面试建议:

复制代码
优先写:快慢指针

因为:

复制代码
空间复杂度 O(1)

九、相关题目推荐

LeetCode 中类似思想题:

复制代码
141. 环形链表
142. 环形链表 II
202. 快乐数
287. 寻找重复数

核心都是:

复制代码
Floyd 判环算法
相关推荐
蛋蛋的就会顺顺的28 分钟前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙35 分钟前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11331 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY1 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录2 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
白山编程大哥2 小时前
Lua 中使用 C 语言的用户自定义类型——userdata
c语言·junit·lua
无敌贵点大王2 小时前
RTThread学习记录13——关于要使用一个外设,RTThread与cubemx到底要怎么配合?
c语言·stm32·学习·rtthread
小O的算法实验室2 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
phltxy3 小时前
C 语言动态内存管理:从申请空间到安全释放
c语言·开发语言·ui
字节跳动的猫3 小时前
LikeShop 积分体系全链路改造:获取规则、订单抵扣与积分商品兑换二开
运维·数据结构