1、求第n个丑数 (质因数只有2,3,5)(leetcode 264)
2、设计算法,找到质因数只有3,5或7的第k个数。
以上两个问题相似
阿里笔试题请设计一个算法,在满足质因数仅为3,5,7或其组合的数中,找出第K大的数。比如K=1,2,3时,分别应返回3,5,7。要求算法时间复杂度最优。
我们可以用3个队列来维护这些数。第1个队列负责乘以3,第2个队列负责乘以5, 第3个队列负责乘以7。算法描述如下:
1. 初始化结果res=1和队列q3,q5,q7
2. 分别往q3,q5,q7插入1*3,1*5,1*7
3. 求出三个队列的队头元素中最小的那个x,更新结果res=x
4. 如果x在:
q3中,那么从q3中移除x,并向q3,q5,q7插入3*x,5*x,7*x
q5中,那么从q5中移除x,并向q5,q7插入5*x,7*x
q7中,那么从q7中移除x,并向q7插入7*x
5. 重复步骤3-5,直到找到第k个满足条件的数
注意,当x出现在q5中,我们没往q3中插入3*x,那是因为这个数在q5中已经插入过了。
#include <iostream>
#include <queue>
using namespace std;
int mini(int a, int b){
return a < b ? a : b;
}
int mini(int a, int b, int c){
return mini(mini(a, b), c);
}
int get_num(int k){
if(k <= 0) return 0;
int res = 1, cnt = 1;
queue<int> q3, q5, q7;
q3.push(3); q5.push(5); q7.push(7);
for(; cnt<k; ++cnt){
int v3 = q3.front();
int v5 = q5.front();
int v7 = q7.front();
res = mini(v3, v5, v7);
if(res == v7){
q7.pop();
}
else{
if(res == v5){
q5.pop();
}
else{
if(res == v3){
q3.pop();
q3.push(3*res);
}
}
q5.push(5*res);
}
q7.push(7*res);
}
return res;
}
int main(){
for(int i=1; i<20; ++i)
cout<<get_num(i)<<endl;
return 0;
}
该方法的具体分析:https://blog.csdn.net/wangfengfan1/article/details/48006071
该问题的另一种思路:https://blog.csdn.net/qingyuanluofeng/article/details/54124669
求第n个丑数 (质因数只有2,3,5)
优化思路:
并不用每次都尝试所有组合,我们需要过滤掉不可能的组合
已知2,3,5与已有丑数相乘时,数值增长速度是不一样的
我们每次从三组新丑数中,挑选大于已知末尾丑数的最小值,来作为新的丑数
乘3或者乘5的新丑数,如果某次未被选中放入数轴,那么肯定有某一刻会被放进去
所以使用三个游标来确定已被放入数轴的新丑数最小值,每次仅需要对比这三个游标与2,3,5乘积即可
首先想一想,丑数是由只含2,3,5的因子组成的,那一个丑数乘上2,3,5仍会得到一个丑数,所以生成新丑数可以以旧丑数为基础,然后乘以2,3,5 得到新的丑数;如何使生成的丑数保持递增的顺序,每次循环会生成一个新丑数,与原来两个旧丑数做比较,取最小的加入数组中。
首先初始化dp[0]=1,第一次循环,dp[0]*2,dp[0]*3,dp[0]*5,取最小2,更新index2 = index2 + 1,第二次循环,dp[1]*2,dp[0]*3,dp[0]*5,取最小3,更新index3 = index3 + 1,第三次循环,dp[1]*2,dp[1]*3,dp[0]*5,取最小4,更新index5 = index5 + 1,如此下去,得出结果
int FindUgly(int n)
{
int* ugly = new int[n];
ugly[0] = 1;
int index2 = 0;
int index3 = 0;
int index5 = 0;
int index = 1; // 维护丑数数组
while (index < n)
{
int val = Min(ugly[index2]*2, ugly[index3]*3, ugly[index5]*5); //竞争产生下一个丑数 (最小)
if (val == ugly[index2]*2) //将产生这个丑数的index*向后挪一位;
++index2;
if (val == ugly[index3]*3) //这里不能用elseif,因为可能有两个最小值,这时都要挪动;
++index3;
if (val == ugly[index5]*5)
++index5;
index = index + 1;
ugly[index] = val;
}
}
7、计算n以内质因数只有3、5、7的数个数
int main() {
long x;
cin >> x;
int sum = -1;
for(long i = 1; i<= x; i *= 7){
for(long j = i; j <= x; j *= 5) {
for(long k = j; k <= x; k *= 3){
++sum;
}
}
}
cout << sum << endl;
return 0;
}