selected_coding_interview/docs/264. 丑数 II .md
根据题意,每个丑数都可以由其他较小的丑数通过乘以 $2$ 或 $3$ 或 $5$ 得到。
所以,可以考虑使用一个优先队列保存所有的丑数,每次取出最小的那个,然后乘以 $2$ , $3$ , $5$ 后放回队列。然而,这样做会出现重复的丑数。例如:
初始化丑数列表 [1]
第一轮: 1 -> 2, 3, 5 ,丑数列表变为 [1, 2, 3, 5]
第二轮: 2 -> 4, 6, 10 ,丑数列表变为 [1, 2, 3, 4, 6, 10]
第三轮: 3 -> 6, 9, 15 ,出现重复的丑数 6
为了避免重复,我们可以用三个指针 $a$ , $b$, $c$ ,分别表示下一个丑数是当前指针指向的丑数乘以 $2$ , $3$ , $5$ 。
利用三个指针生成丑数的算法流程:
<,,,,,,,,,,>
class Solution:
def nthUglyNumber(self, n: int) -> int:
res, a, b, c = [1] * n, 0, 0, 0
for i in range(1, n):
n2, n3, n5 = res[a] * 2, res[b] * 3, res[c] * 5
res[i] = min(n2, n3, n5)
if res[i] == n2: a += 1
if res[i] == n3: b += 1
if res[i] == n5: c += 1
return res[-1]
class Solution {
public int nthUglyNumber(int n) {
int a = 0, b = 0, c = 0;
int[] res = new int[n];
res[0] = 1;
for(int i = 1; i < n; i++) {
int n2 = res[a] * 2, n3 = res[b] * 3, n5 = res[c] * 5;
res[i] = Math.min(Math.min(n2, n3), n5);
if (res[i] == n2) a++;
if (res[i] == n3) b++;
if (res[i] == n5) c++;
}
return res[n - 1];
}
}
class Solution {
public:
int nthUglyNumber(int n) {
int a = 0, b = 0, c = 0;
int res[n];
res[0] = 1;
for(int i = 1; i < n; i++) {
int n2 = res[a] * 2, n3 = res[b] * 3, n5 = res[c] * 5;
res[i] = min(min(n2, n3), n5);
if (res[i] == n2) a++;
if (res[i] == n3) b++;
if (res[i] == n5) c++;
}
return res[n - 1];
}
};