题目描述
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路
题目很简单,就是一个数的公约数是由多个2多个3多个5相乘得到的,不能有其它公约数。
①打表
遍历前1百万个数,把丑数统计出来,如何判断一个数据是不是丑数?只要能被5整除就一直除,只要能被3整除也一直除,只要能被2整除也一直除,知道最后结果是不是为1,若为1就是丑数,不为1就不是丑数。定义一个数组存储这些结果,然后直接输出就行,freopen函数很好用(int范围内就1691个)。
②set集合(自动排序)
定义一个set,把1插进去(能自动排序和去除重复),每次取出最小值,然后把该数的2倍、3倍、5倍插进去,依次类推,取道你要求的第N个丑数为止(这个思路,有个bug,就是数据越界,并且存储的数据要远远大于要求的N,在添加的时候,需要一个越界判断处理,注意不能用乘,要用除)。
③数组下标,3个指针指向最低位,通过比较最优的后移。
代码
#include<stdio.h>
int main(){
//freopen("1.txt","r",stdin);
//freopen("1.txt","w",stdout);
int a[1692]={0,1}; //int范围内总共有1691个
int j=2;
//int MAX=1<<31-1; //error,只是求1<<30
int MAX=(1<<31)-1; //int类型的最大值
printf("%d\n",MAX);
for(int i=2;i<=MAX;i++){
int x=i;
while(x%2==0) x/=2;
while(x%3==0) x/=3;
while(x%5==0) x/=5;
if(x==1) a[j++]=i;
if(i==MAX) break; //不加这个,for循环出不去,越界了
}
printf("%d\n",j);
for(int i=1;i<j;i++){
// printf("%d,",a[i]); //全部写入文本1.txt中
}
//while(~scanf("%d",&j)){} //从文本1.txt中读
return 0;
}
#include<stdio.h>
#include<set>
#include<iostream>
using namespace std;
/**
《set操作》
插入
取出
遍历
卡边界,就不能通过
*/
int main(){
int n;
while(~scanf("%d",&n)){
/*set<long long int> a;
a.insert(1);
long long int x;
while(n--){
//取出
x=*a.begin();
a.erase(x); //删除值x
if(n==0) break;
a.insert(x*2);
a.insert(x*3);
a.insert(x*5);
}
printf("%d\n",x);*/
set<int> a;
a.insert(1);
int x;
int MAX=((1<<31)-1); //int类型的最大值
while(n--){
//取出
x=*a.begin();
if(n==0) break;
a.erase(x); //删除值x
//cnm,一直坑,不能用乘,要用除,越界变成负数了
//if(x*2<=MAX) a.insert(x*2);
if(x<=MAX/2) a.insert(x*2);
if(x<=MAX/3) a.insert(x*3);
if(x<=MAX/5) a.insert(x*5);
}
printf("%d\n",x);
}
}
#include<stdio.h>
int min(int a,int b,int c){
return a<b?(a<c?a:c):(b<c?b:c);
}
int main(){
int a[1546]={0,1};
int index2=1,index3=1,index5=1;
int n,i=1;
while(scanf("%d",&n)!=EOF){
while(1){
if(i==n) break;
int x=min(a[index2]*2,a[index3]*3,a[index5]*5);
if(x==a[index2]*2) index2++;
if(x==a[index3]*3) index3++;
if(x==a[index5]*5) index5++;
a[++i]=x;
}
printf("%d\n",a[n]);
}
return 0;
}
总结:方法一比较简单,就是一个暴力打表,方法二是利用set辅助,注意越界处理,并且内存消耗比较大,即使找到了第N个,后面也求出了很多,第三种方法是最优的,只求到当前N即可(设计的很巧妙,三个指针风别固定乘2乘3乘5,每次取最小哦啊和对应指针后移)。