这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战
丑数
我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:
输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 说明:
1 是丑数。 n 不超过1690。
题解
方法一:动态规划——Java
根据题目对 丑数 的定义。
我们可以知道,用 丑数 * (2、3、5) 会得到另外三个丑数。
也就是说:一个丑数生成3个新丑数。
我们定义三个变量: a2 a3 a5三个变量表示 当前丑数 是否使用 2 3 5 这三个数生成新的丑数; 当一个丑数使用过 2 3 5 中的任意的一个数后,就 没有资格 再用它和 使用过的数 去生成新丑数。
比如: 丑数A, (A * 2)会生成一个新的丑数,那么 丑数A 就没有资格再与 2 相乘得到另一个丑数,只能与 3、5 。
那么每次我们从 将要生成的丑数中找出最小的那个进行排序,就能得到一个丑递增顺序数组。 当生成第 n 个丑数后,直接返回就可以。
比如从1开始:
a2 a3 a5 分别表示 丑数1 还没有被 2 3 5 使用,生成新的丑数。
从将要生成新的丑数里面选一个最小的,当最新的丑数,也就是 2。
此时丑数1 的 a2 被使用过了,那么 a2 就指向下一个 丑数2。
此时 a2 表示 丑数2 没使用 2 来新成丑数,a3 a5 表示 丑数1 还没有被 3 5 使用,生成新的丑数。
依次往下....
class Solution {
public int nthUglyNumber(int n) {
int[] dp = new int[n];
int a = 0, b = 0, c = 0;
dp[0] = 1;
for (int i = 1; i < n; i++) {
int f2 = dp[a] * 2;
int f3 = dp[b] * 3;
int f5 = dp[c] * 5;
dp[i] = Math.min(Math.min(f2, f3), f5);
if (dp[i] == f2) {
a++;
}
if (dp[i] == f3) {
b++;
}
if (dp[i] == f5) {
c++;
}
}
return dp[n - 1];
}
}
方法一:动态规划——Go
func nthUglyNumber(n int) int {
dp := make([]int, n+1)
dp[1] = 1
p2, p3, p5 := 1, 1, 1
for i := 2; i <= n; i++ {
x2, x3, x5 := dp[p2]*2, dp[p3]*3, dp[p5]*5
dp[i] = min(min(x2, x3), x5)
if dp[i] == x2 {
p2++
}
if dp[i] == x3 {
p3++
}
if dp[i] == x5 {
p5++
}
}
return dp[n]
}
func min(a, b int) int {
if a < b {
return a
}
return b
}