问题描述
我们把只包含质因子2、3和5的数称为丑数。求按从小到大的顺序的第n个丑数。
解题报告
由于丑数 只 包含质因子2,3,5,因此较大的丑数可以由较小的丑数依次乘以上述质因子得到。
优先队列
同时构建一个优先队列和集合。
每次从队列中取出一个最小的数,将这个数依次乘以三个因子,然后判断三个新得的三个数是否在集合中,如果不在集合中,则将它们插入集合中以及压入优先队列中,最后将取出的那个数从队列中弹出。
动态规划
,所以我们持续更新 三个索引:
。
更新方法是:
判断
谁最小,则将对应的索引往后移一位。
思想是:对于一系列顺序生成的丑数,它们是前面的丑数依次乘以三个质因子中的一个生成的。
以质因子2的索引为例:一个丑数乘以2之后,下一次乘以2必定是该丑数的下一个丑数,也即对应的索引加一。
实现代码
优先队列
class Solution {
public:
int nthUglyNumber(int n) {
priority_queue<long long,vector<long long>, greater<long long>> pq;
set<long>s;
long long factor[3]={2, 3, 5},ans=1;
for (int i=0;i<3;i++) {
pq.push(factor[i]);
s.insert(factor[i]);
}
for (int i = 1; i < n; i++) {
ans = pq.top();
pq.pop();
for (int j = 0; j < 3; j++) {
if (s.find(ans * factor[j])==s.end()) {
pq.push(ans * factor[j]);
s.insert(ans * factor[j]);
}
}
}
return (int)ans;
}
};
动态规划
class Solution{
public:
int nthUglyNumber(int n){
vector<int>dp(n,0);
dp[0]=1;
int p2=0,p3=0,p5=0;
for(int i=1;i<n;i++){
dp[i]=min(dp[p2]*2,min(dp[p3]*3,dp[p5]*5));
if(dp[i]==dp[p2]*2) p2++;
if(dp[i]==dp[p3]*3) p3++;
if(dp[i]==dp[p5]*5) p5++;
}
return dp[n-1];
}
};
参考资料
[1] Leetcoed 面试题49.丑数
[2] 题解区:Jerry