题目描述
思路解析动画文字版
记住两件事:① 反复求数位平方和往下走;② 用 seen 记住走过的数,撞见重复就是死循环。下面先演一个快乐的,再演一个不快乐的。
A · 起点 n = 7:先看一个快乐的例子:从 7 开始。下面这串是它将要走过的链,seen 集合现在还是空的。
A · 处理 7:指针停在 7。先在 seen 里查 7——没见过,把它记进 seen,接着算它的各数位平方和。
A · 7 → 49:算 7 的数位平方和:7² = 49 = 49。下一个数是 49,指针往后挪一格继续。
A · 处理 49:指针停在 49。先在 seen 里查 49——没见过,把它记进 seen,接着算它的各数位平方和。
A · 49 → 97:算 49 的数位平方和:4² + 9² = 16 + 81 = 97。下一个数是 97,指针往后挪一格继续。
A · 处理 97:指针停在 97。先在 seen 里查 97——没见过,把它记进 seen,接着算它的各数位平方和。
A · 97 → 130:算 97 的数位平方和:9² + 7² = 81 + 49 = 130。下一个数是 130,指针往后挪一格继续。
A · 处理 130:指针停在 130。先在 seen 里查 130——没见过,把它记进 seen,接着算它的各数位平方和。
A · 130 → 10:算 130 的数位平方和:1² + 3² + 0² = 1 + 9 + 0 = 10。下一个数是 10,指针往后挪一格继续。
A · 处理 10:指针停在 10。先在 seen 里查 10——没见过,把它记进 seen,接着算它的各数位平方和。
A · 10 → 1:算 10 的数位平方和:1² + 0² = 1 + 0 = 1。下一个数是 1,指针往后挪一格继续。
A · 走到 1,快乐数:链一路走到了 1。到 1 就停下,7 是快乐数,返回 true。
B · 换个起点 n = 2:再看一个不快乐的例子:从 2 开始。这串链最后会绕回一个见过的数——那就是死循环的信号。
B · 处理 2:指针停在 2。seen 里没有 2,把它记进去,再算它的各数位平方和。
B · 2 → 4:算 2 的数位平方和:2² = 4 = 4。下一个数是 4,继续往后走。
B · 处理 4:指针停在 4。seen 里没有 4,把它记进去,再算它的各数位平方和。
B · 4 → 16:算 4 的数位平方和:4² = 16 = 16。下一个数是 16,继续往后走。
B · 处理 16:指针停在 16。seen 里没有 16,把它记进去,再算它的各数位平方和。
B · 16 → 37:算 16 的数位平方和:1² + 6² = 1 + 36 = 37。下一个数是 37,继续往后走。
B · 处理 37:指针停在 37。seen 里没有 37,把它记进去,再算它的各数位平方和。
B · 37 → 58:算 37 的数位平方和:3² + 7² = 9 + 49 = 58。下一个数是 58,继续往后走。
B · 处理 58:指针停在 58。seen 里没有 58,把它记进去,再算它的各数位平方和。
B · 58 → 89:算 58 的数位平方和:5² + 8² = 25 + 64 = 89。下一个数是 89,继续往后走。
B · 处理 89:指针停在 89。seen 里没有 89,把它记进去,再算它的各数位平方和。
B · 89 → 145:算 89 的数位平方和:8² + 9² = 64 + 81 = 145。下一个数是 145,继续往后走。
B · 处理 145:指针停在 145。seen 里没有 145,把它记进去,再算它的各数位平方和。
B · 145 → 42:算 145 的数位平方和:1² + 4² + 5² = 1 + 16 + 25 = 42。下一个数是 42,继续往后走。
B · 处理 42:指针停在 42。seen 里没有 42,把它记进去,再算它的各数位平方和。
B · 42 → 20:算 42 的数位平方和:4² + 2² = 16 + 4 = 20。下一个数是 20,继续往后走。
B · 处理 20:指针停在 20。seen 里没有 20,把它记进去,再算它的各数位平方和。
B · 20 → 4:算 20 的数位平方和:2² + 0² = 4 + 0 = 4。下一个数是 4,继续往后走。
B · 4 又出现了 → 死循环:轮到 4 时先查 seen——4 早就记过了(绿色那格)!这说明从这里开始会无限绕圈,永远到不了 1,2 不是快乐数,返回 false。
三个高频追问:seen 的必要性、快慢指针的 O(1) 替代法、以及那个唯一的不快乐循环。
参考代码
def isHappy(n): seen = set() # 记录见过的数 while n != 1 and n not in seen: # 没到 1 且没循环就继续 seen.add(n) n = sum(int(d)**2 for d in str(n)) # 各数位平方和 return n == 1 # 停在 1 = 快乐数复杂度
- 时间:O(log n),几步内数就缩到三位数以内,之后路径长度有上界,整体接近常数级
- 空间:O(log n),seen 集合最多存下路径上出现过的那些数,数量有限
易错点
面试追问把动画讲成自己的话
追问为什么需要 seen 集合,去掉行不行?
追问除了 seen 集合,还有别的判循环方法吗?
追问所有不快乐的数最后都会进同一个循环吗?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
加一
LeetCode 66 · 简单 · 沿着 数学 & 几何 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题