开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情
264. 丑数 II 题目描述:给你一个整数 n ,请你找出并返回第 n 个 丑数 。丑数 就是只包含质因数 2、3 和/或 5 的正整数。。
| 示例1 | 示例2 |
|---|---|
| 输入: 输出: 解释: 是由前 个丑数组成的序列。 | 输入: 输出: 解释: 通常被视为丑数。 |
中规中矩的动态规划
正向思维方法:判断每一个数是否是丑数,如果是,记录当前数字,并将计数器 。如果计算器此时等于 ,返回当前数字即可。如何判断一个数是否是丑数,可参考 # 263. 丑数。本文将采用动态规划的思想来求解第 个丑数。
1、确定 dp 状态数组
定义 是第 i 个丑数,其中 。
NOTE: 为方便计算, 第 位的元素当作哨兵节点,不介入整个状态的转移过程。
2、确定 dp 状态方程
试想丑数是如何计算出来:假设有一个指针 ,初始状态 (也是第一个丑数);既然丑数只能有、、 三个因子,那就从初始状态 不断去 (即,,,),或者是 2、3、5之间的组合(即,,,)。为保证计算出来的丑数保持相对大小顺序,运算时应取计算结果的最小值。
定义三个指针 、、,起始状态为 。对于 存在,
如果此时,
- ,说明第 i 个丑数归位,此时 指针向前移动一位,即 ;
- ,说明第 i 个丑数归位,此时 指针向前移动一位,即 ;
- ,说明第 i 个丑数归位,此时 指针向前移动一位,即 ;
3、确定 dp 初始状态
代表第 个丑数,即 ;
4、确定遍历顺序
从 遍历到 ;
5、确定最终返回值
是第 个丑数,即为最终返回值。
6、代码示例
/**
* 空间复杂度 O(n)
* 时间复杂度 O(n)
*/
function nthUglyNumber(n: number): number {
const dp = new Array(n + 1).fill(0);
dp[1] = 1;
let p2 = 1, p3 = 1, p5 = 1;
for (let i = 2; i <= n; i++) {
const num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
dp[i] = Math.min(num2, num3, num5);
if (dp[i] === num2) {
p2++;
} else if (dp[i] === num3){
p3++;
} else if (dp[i] === num5) {
p5++;
}
}
return dp[n];
};