LeetCode 264中等动态规划
丑数 II 图解题解
这道题到底在问什么
给你一个整数 n,请你找出并返回第 n 个丑数。丑数就是质因子只包含 2、3 和 5 的正整数。1 通常被视为丑数。
- 输入
- n = 10
- 输出
- 12
- 解释
- [1,2,3,4,5,6,8,9,10,12] 是前 10 个丑数。
- 输入
- n = 1
- 输出
- 1
最优解:一步一步想明白
- 3丑数序列本身是有结构的:已有丑数乘 2、乘 3、乘 5 仍然是丑数。我们应该只在丑数候选里推进。
- 4不变量:dp[0..i-1] 已经是递增且不重复的前 i 个丑数;p2、p3、p5 分别指向下一次乘 2、3、5 时还没被使用的位置。
- 5执行:dp = [1] * n; p2 = p3 = p5 = 01 被视为第一个丑数。三个指针都从 0 出发,表示下一批候选分别是 2、3、5。
- 6执行:nxt = min(2,3,5); dp[1] = 2; p2 += 1最小候选是 2,放进 dp[1]。因为 2 来自 p2 这条线,所以 p2 前进,避免下次还生成 2。
- 7执行:dp[2] = 3; p3 += 1p2 已经指向 dp[1]=2,所以乘 2 候选变成 4。当前最小是 3,p3 前进。
- 8执行:dp[3] = 4; p2 += 14 是 2 乘 2 得到的丑数。填入后 p2 继续前进,下一次乘 2 会看 dp[2]=3。
- 9执行:dp[4] = 5; p5 += 15 只来自乘 5 这条线,所以只移动 p5。现在前五个丑数是 1、2、3、4、5。
- 10执行:dp[5] = 66 很关键:它既可以由 3×2 得到,也可以由 2×3 得到。如果只移动一个指针,下一轮会再生成一次 6。
- 11执行:if a==nxt: p2 += 1; if b==nxt: p3 += 1去重靠的就是“所有命中的指针都动”。代码必须写三个独立 if,不能写成 if/elif/elif。
- 12执行:dp[6] = 8; p2 += 1指针移动后,下一批候选自然跳过了重复的 6,继续得到 8。
- 13执行:dp[7] = 9; p3 += 19 来自 3×3,填入后 p3 前进。dp 始终保持递增。
- 14执行:dp[8] = 10; p2 += 1; p5 += 110 也是重复候选:5×2 和 2×5 都能得到它,所以 p2、p5 必须一起移动。
- 15执行:dp[9] = 12; return dp[-1]第 10 格填入 12,和题目示例一致。真实代码会一直填到第 n 格,最后返回 dp[-1]。
- 18看到“由已有结果乘几个固定因子生成下一个最小值”,可以联想到多路合并和指针去重。
⚠️ 容易写错的地方
✗ 错:把 1 排除在丑数外
✓ 对:初始化 dp[0] = 1
题目说明 1 通常被视为丑数,n=1 时答案就是 1。
✗ 错:指针更新写成 if/elif/elif
✓ 对:三个独立 if 都要检查
6、10、12 这类数会同时来自多条路径,只移动一个指针会重复。
✗ 错:每轮把三个候选都加入 dp
✓ 对:每轮只加入最小候选 nxt
dp 必须保持递增且不重复。
✗ 错:用逐个整数试除
✓ 对:用 dp + 三指针直接生成丑数序列
逐个试除会浪费大量非丑数候选。
完整代码(Python)
Python
class Solution:
def nthUglyNumber(self, n):
dp = [1] * n
p2 = p3 = p5 = 0
for i in range(1, n):
a = dp[p2] * 2
b = dp[p3] * 3
c = dp[p5] * 5
nxt = min(a, b, c)
dp[i] = nxt
if a == nxt:
p2 += 1
if b == nxt:
p3 += 1
if c == nxt:
p5 += 1
return dp[-1]复杂度
时间复杂度
O(n)
每一轮生成一个新的丑数,总共生成 n 个。
空间复杂度
O(n)
dp 数组保存前 n 个丑数。
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 丑数 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「动态规划」,换最直接的暴力解会差在哪?+
动态规划抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。