🧠 小哆啦解题记 —— 谁偷走了我的快乐?

📅 小哆啦刷题 Day 37

题号:202. 快乐数 - 力扣(LeetCode)

关键词:数位平方和、哈希判环、数学循环论证、无限循环解释


第一章:大雄的灵魂发问

"哆啦A梦,最近怎么也开心不起来......难道我......不是个快乐数?"

大雄满脸迷茫地趴在课桌上。

哆啦A梦吃着铜锣烧冷静回答:"来,我带你刷一道题,看看你到底'快乐不快乐'。"


第二章:题目来了

给你一个正整数 n,重复如下操作:

  • 将其每一位数字的平方求和,得出新数。
  • 不断重复此过程。

如果最终可以变成 1,就是快乐数

如果陷入无限循环 却始终得不到 1,那就很遗憾,它不是快乐数


第三章:大雄的第一版代码(带点 Bug)

typescript 复制代码
function isHappy(n: number): boolean {
    let numMap: Map<number, number> = new Map();
    while (true) {
        let str = n.toString();
        n = str.split("").reduce((acc, cur) => acc + Math.pow(Number(cur), 2), 0);
        if (n == 1) return true;
        if (numMap.has(n)) return false;
        numMap.set(Number(str), n);
    }
}

"我每出现一个数就记录一下,如果又出现了,说明在无限转圈。"大雄自信地说。

哆啦A梦一边擦眼镜一边点头:"嗯......基本思路对,但你这 Map 存得太复杂,Set 更合适。"


第四章:哆啦A梦的快乐优化器

于是他甩出优化后的版本:

ini 复制代码
function isHappy(n: number): boolean {
    const seen = new Set<number>();
    while (n !== 1) {
        if (seen.has(n)) return false;
        seen.add(n);
        n = getNext(n);
    }
    return true;
}

function getNext(num: number): number {
    let sum = 0;
    while (num > 0) {
        const digit = num % 10;
        sum += digit * digit;
        num = Math.floor(num / 10);
    }
    return sum;
}

"每次记录出现过的数,只要你再走进来一次,就说明------你在绕圈。"


第五章:大雄困惑了:为什么就一定会循环?

"等等等等......你说 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 是循环,那为啥一定会循环?为啥不能一直变大,或者跑到 1e10?"

哆啦A梦收起铜锣烧,郑重地回答:


🧠 第六章:无限循环的数学机制,正式揭晓

🧩 一、每一步"变换"都有上限!

你以为这些数字会无限增长?错!

👉 最大增长速率远小于原数值本身。

比如一个 4 位数 9999,变换后是:

ini 复制代码
9² + 9² + 9² + 9² = 81 × 4 = 324

✨ 所以,不管你是 999999999 还是 9999,最终都收敛到一个相对较小的数。

实验证明:任意正整数,变换后最终都会收敛到 ≤ 243。

所以你最多只会经历 243 个不同状态,一旦遇到重复,就铁定进入循环!


🌀 二、经典环:不快乐循环的"死亡八卦阵"

试试 n = 2,看它怎么绕回自己:

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

恭喜,它回到 4 了,这就是经典的"非快乐数死循环"


第七章:进阶姿势·快慢指针

如果你不想用额外空间,那就用链表判环那一套------快慢指针

ini 复制代码
function isHappy(n: number): boolean {
    let slow = n, fast = getNext(n);
    while (fast !== 1 && slow !== fast) {
        slow = getNext(slow);
        fast = getNext(getNext(fast));
    }
    return fast === 1;
}

就像两只赛跑的仓鼠,一快一慢在圆环里转,如果能碰头,就说明陷入循环了。


第八章:终章·算法与人生的哲学

静香眨了眨眼:"那你们说,人类的快乐,是不是也能像这样判定?"

哆啦A梦认真回答:"如果你重复做一些事,却永远得不到满足,可能你已经掉进了非快乐循环。"


✅ 小哆啦的技术小结

解法 判环方式 时间复杂度 空间复杂度 特点
哈希表判环 Set 记录状态 O(logN) O(logN) 简单直观,好调试
快慢指针 空间优化 O(logN) O(1) 进阶思维,链表判环思想迁移

🎓 总结一句话

不是每一个数都有快乐结局,但每一个循环都有逃出生天的可能。

相关推荐
Owen_Q7 分钟前
Leetcode百题斩-二分搜索
算法·leetcode·职场和发展
矢志航天的阿洪28 分钟前
蒙特卡洛树搜索方法实践
算法
UnderTheTime1 小时前
2025 XYD Summer Camp 7.10 筛法
算法
zstar-_1 小时前
Claude code在Windows上的配置流程
笔记·算法·leetcode
圆头猫爹1 小时前
第34次CCF-CSP认证第4题,货物调度
c++·算法·动态规划
秋说1 小时前
【PTA数据结构 | C语言版】出栈序列的合法性
c语言·数据结构·算法
用户40315986396632 小时前
多窗口事件分发系统
java·算法
用户40315986396632 小时前
ARP 缓存与报文转发模拟
java·算法
hi0_62 小时前
03 数组 VS 链表
java·数据结构·c++·笔记·算法·链表
aPurpleBerry2 小时前
hot100 hot75 栈、队列题目思路
javascript·算法