丑数 II:动态规划在数字问题中的应用
给你一个整数 n
,请你找出并返回第 n
个 丑数 。
丑数 就是只包含质因数 2
、3
和/或 5
的正整数。
示例 1:
输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。
示例 2
输入:n = 1 输出:1 解释:1 通常被视为丑数。
动态规划解法:
丑数只包含质因数 2、3、5,每一个丑数由之前的丑数乘 2 或 3 或 5 得到,因此适用于动态规划解法,定义长度为 n 的 dp 数组存放所有丑数。例如,第 1 个丑数为 1,第 2 个丑数为 1 * 2,第 3 个丑数为 1 * 3,第 4 个丑数为 2 * 2, 第 5 个丑数为 1 * 5,以此类推。
要找到第 n 个丑数,难点在于需要从小到大找到第 n 个丑数。由上述方法,根据第 1 个丑数 1 乘质因子得到 2、3、5,根据第 2 个丑数 2 乘质因子得到 4、6、10,4 在 5 之前,涉及到丑数从小到大顺序的问题。
解决方法为:设定三个指针 p2,p3,p5(初始时均为 1),表示目前还没有乘过 2、3、5 的丑数位置。下一个丑数由三个指针所指向的丑数乘对应的 2 或 3 或 5 中的最小值,表示下一个丑数为之前的丑数乘 2、3、5 三个质因子之一所得到,且保证所有丑数从小到大排列的顺序。再判断下一个丑数具体为 dp[p2] * 2、 dp[p3] * 3、dp[p5] * 5 中的哪一个,将对应的指针 p ++,表示其位置的丑数已经乘过了相应的质因子,无需再乘。最终返回 dp 数组最后一个数,即为第 n 个丑数。
class Solution {
public:
int nthUglyNumber(int n) {
int p2 = 0, p3 = 0, p5 = 0;
vector<int> dp(n);
dp[0] = 1;
for(int i = 1; i < n; i++){
int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
dp[i] = min(min(num2, num3), num5);
if(dp[i] == num2) p2++;
if(dp[i] == num3) p3++;
if(dp[i] == num5) p5++;
}
return dp[n - 1];
}
};