264. 丑数 II(优先队列三指针)
Posted mp-ui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了264. 丑数 II(优先队列三指针)相关的知识,希望对你有一定的参考价值。
264. 丑数 II
难度中等700收藏分享切换为英文接收动态反馈
给你一个整数 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
法一:优先队列
最直观的方法,先创建一个优先队列,因为第一个丑数是1,所以把1加入优先队列。接下来就不断地取出优先队列的第1个数,再分别乘以2/3/5放入。
这样,第n个取出的就是我们要的答案。
为了去除重复,我们用一个last
来代表我们上一步取出的值,如果这一次取出的和上一次取出的一样的话就不计数。
代码:
class Solution {
public int nthUglyNumber(int n) {
PriorityQueue<Long> queue = new PriorityQueue<>();
queue.add(1L);
int cnt = 0;
long last = 0; //上一个取出的
while(!queue.isEmpty()){
long i = queue.poll();
if(i == last){
//避免重复
continue;
}
last = i;
++cnt;
if(cnt == n){
return (int)i;
}
queue.offer(i * 2);
queue.offer(i * 3);
queue.offer(i * 5);
}
return 0;
}
}
运行结果:
法二:三指针
思路:丑数只包含2/3/5这三个因子,且第一个丑数是1,那么就可以从第一个丑数开始,每一个都分别乘以2/3/5而得到新的丑数。
先定义dp[i] 为第i个丑数,根据定义,dp[1] = 1
,为了保证数组是递增的,采取以下方法:
- 定义三个指针:
index2
/index3
/index5
,表示还没有乘过2/3/5的最小丑数 dp[index2]*2
/dp[index3]*3
/dp[index5]*5
就是我们这一轮生成的3个丑数- 在生成的三个丑数中取出最小的那个放到
dp[i]
的位置,并把对应的index++
同时还要注意去重
代码:
class Solution {
public int nthUglyNumber(int n) {
int[] dp = new int[n + 1];
dp[1] = 1; //第一个丑数是1
int index2 = 1; //还没乘过2的最小丑数的位置
int index3 = 1; //还没乘过3的最小丑数的位置
int index5 = 1; //还没乘过5的最小丑数的位置
for (int i = 2; i <= n; i++) {
int a = dp[index2] * 2;
int b = dp[index3] * 3;
int c = dp[index5] * 5;
dp[i] = Math.min(a, Math.min(b, c));
if(dp[i] == a){
++index2;
}else if(dp[i] == b){
++index3;
}else{
++index5;
}
//去重
if(dp[i] <= dp[i-1]){
--i;
}
}
return dp[n];
}
}
运行结果:
延伸题目:313. 超级丑数
难度中等174收藏分享切换为英文接收动态反馈
超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 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
中的所有值都 互不相同 ,且按 递增顺序 排列
n指针解法
思路和上面的三指针是一样的,上面是只定义三个指针,这次直接定义primes.length个指针
代码:
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
int[] index = new int[primes.length];
Arrays.fill(index, 1);
int[] dp = new int[n + 1];
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = 0x7fffffff;
for (int j = 0; j < index.length; j++) {
dp[i] = Math.min(dp[i], dp[index[j]] * primes[j]);
}
for (int j = 0; j < index.length; j++) {
if(dp[i] == dp[index[j]] * primes[j]){
++index[j];
}
}
}
return dp[n];
}
}
还有就是关于去重,到这里我就想明白了,上面的三指针的代码是这样子的:
因为dp数组本身就是按照从小到大的顺序排的,其实有可能解出的a/b/c是一样的,只要把下面的三个if判断都改成独立的就行了,不要else if
这种形式,就可以去重。
int a = dp[index2] * 2;
int b = dp[index3] * 3;
int c = dp[index5] * 5;
dp[i] = Math.min(a, Math.min(b, c));
if(dp[i] == a){
++index2;
}else if(dp[i] == b){
++index3;
}else{
++index5;
}
//去重
if(dp[i] <= dp[i-1]){
--i;
}
运行结果:
以上是关于264. 丑数 II(优先队列三指针)的主要内容,如果未能解决你的问题,请参考以下文章