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
解一:小顶堆
既然要按从小到大排序,就利用小顶堆(优先队列)的性质实现自动排序:
- 起始先将最小丑数
1
放入队列 - 每次从队列取出最小值
x
,然后将x
所对应的丑数2x、3x
和5x
进行入队。 - 对步骤2循环多次,第
n
次出队的值即是答案。
为了防止同一丑数多次进队,我们需要使用数据结构Set
来记录入过队列的丑数。
查看代码
class Solution {
public:
int nthUglyNumber(int n) {
priority_queue<long,vector<long>,greater<long>> pque;//小顶堆
int factors[3]={2,3,5};//三个因子
unordered_set<long> flag;//是否加入过的标志位
flag.insert(1L);
pque.push(1L);
int res=0;
for(int i=0;i<n;i++){
long cur=pque.top();
res=(int)cur;
pque.pop();
for(int j=0;j<3;j++){//依次得到cur*当前因子
long next=factors[j]*cur;
if(!flag.count(next)){//判断是否加入
flag.insert(next);
pque.push(next);
}
}
}
return res;
}
};
解二:多指针
来自这里
- 由丑数*3所得的有序序列:
1*3、2*3、3*3、4*3、5*3、6*3、8*3.…
- 由丑数*5所得的有序序列:
1*5、2*5、3*5、4*5、5*5、6*5、8*5.…
举个例子,假设我们需要求得[1,2,3…,10,12]
丑数序列arr
的最后一位,那么该序列可以看作以下三个有序序列归并而来:
- 1*2,2*2,3*2…,10*2,12*2,将2提出,即
arr*2
- 1*3,2*3,3*3,…,10*3,12*3,将3提出,即
arr*3
- 1*5,2*5,3*5…,10*5,12*5,将5提出,即
arr*5
因此我们可以使用三个指针来指向目标序列arr
的某个下标,使用arr下标*质因数代表当前使用到三个有序序列中的哪一位,同时使用idx
表示当前生成到arr
哪一位丑数。
查看代码
class Solution {
public:
int nthUglyNumber(int n) {
int res[n];//按顺序记录丑数
res[0]=1;//下标从0开始,第一个丑数是1
int idx2,idx3,idx5;//三个序列的下标初始为0
idx2=idx3=idx5=0;
for(int i=1;i<n;i++){//依次计算第i+1个丑数
long cur2=res[idx2]*2;//如果下标生成新的丑数
long cur3=res[idx3]*3;
long cur5=res[idx5]*5;
long next=min(cur2,min(cur3,cur5));//选择最小的作为第i+1个丑数
if(cur2==next)//因为next可能不止被一个序列覆盖,所以没有else
idx2++;
if(cur3==next)
idx3++;
if(cur5==next)
idx5++;
res[i]=(int)next;//记录第i+1个丑数
}
return res[n-1];//返回第n个丑数
}
};