丑数(时间空间效率的平衡)

题目描述

把只包含因子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,每次取最小哦啊和对应指针后移)。

猜你喜欢

转载自blog.csdn.net/hqh131360239/article/details/80927097
今日推荐