264. 丑数 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 通常被视为丑数。
提示:
- 1 <= n <= 1690
思路:
方法一:使用优先队列 + 集合去重
方法二:使用多路归并,本质上是DP
// 多路归并
class Solution {
public int nthUglyNumber(int n) {
int[] p = new int[n];
p[0] = 1;
int x = 0, y = 0, z = 0;
for (int i = 1; i < n; i++) {
int a = p[x] * 2, b = p[y] * 3, c = p[z] * 5;
int min = Math.min(a, Math.min(b, c));
if (a == min) x++;
if (b == min) y++;
if (c == min) z++;
p[i] = min;
}
return p[n - 1];
}
}
313. 超级丑数
超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。
给你一个整数 n 和一个整数数组 primes ,返回第 n 个 超级丑数 。
题目数据保证第 n 个 超级丑数 在 32-bit 带符号整数范围内。
示例 1:
输入:n = 12, primes = [2,7,13,19] 输出:32 解释:给定长度为 4 的质数数组 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。
示例 2:
输入:n = 1, primes = [2,3,5] 输出:1 解释:1 不含质因数,因此它的所有质因数都在质数数组 primes = [2,3,5] 中。
提示:
1 <= n <= 106
1 <= primes.length <= 100
2 <= primes[i] <= 1000
- 题目数据 保证 primes[i] 是一个质数
- primes 中的所有值都 互不相同 ,且按 递增顺序 排列
// 暴力多路归并
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
int[] res = new int[n];
res[0] = 1;
int[] p = new int[primes.length];
for (int i = 1; i < n; i++) {
int min = Integer.MAX_VALUE;
for (int j = 0; j < p.length; j++) {
if (res[p[j]] * primes[j] < min)
min = res[p[j]] * primes[j];
}
res[i] = min;
for (int j = 0; j < p.length; j++)
if (res[p[j]] * primes[j] == min)
p[j]++;
}
return res[n - 1];
}
}
// 堆优化的多路归并
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
PriorityQueue<int[]> q = new PriorityQueue<>((o1, o2) -> (o1[0] - o2[0]));
for (int i = 0; i < primes.length; i++) {
q.offer(new int[]{primes[i], i, 1});
}
int[] res = new int[n];
res[0] = 1;
for (int i = 1; i < n;) {
int[] p = q.poll();
if (p[0] != res[i - 1]) res[i++] = p[0];
q.offer(new int[]{res[p[2]] * primes[p[1]], p[1], p[2] + 1});
}
return res[n - 1];
}
}
986. 区间列表的交集
二路归并