每日一算法---寻找丑数

题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第1500个丑数。

  分析:寻找一个数是不是满足某种数(质数,水仙数)等,最简单的方法就是遍历,对于任意一个丑数必定可以写成2^m*3^n*5^p,因而对于一个丑数,只含有2,3,5因子,也就意味着该数number%2==0;number%3==0;number%5==0,如果一个数能被2整除,我们就连续除以2;能被3整除,我们就连续除以3;能被5整除,我们就连续除以5;如果最后得到1,则该数是素数,否则是丑数。

#include<stdio.h>
//判断一个给定的数number是否是丑数
int IsUgly(int number)
{
    while(number % 2 == 0)
    {
        number /= 2;
    }
    while(number % 3 ==0)
    {
        number /= 3;
    }
    while(number % 5 ==0)
    {
        number /= 5;
    }
    return(number == 1)?1:0;
}

//返回从1开始第index个丑数
int GetUglyNumber(int index)
{
    if(index <= 0)
    {
        return 0;
    }

    int number=0;
    int count=0;
    while(count < index)
    {
        ++number;
        if(IsUgly(number))
        {    
            ++count;
        }

    }

    return number;
}

int main()
{
    int idx = 0;
    printf("Enter A Number:");
    scanf("%d",&idx);
    printf("%d",GetUglyNumber(idx));
    printf("\n");

    return 0;
}

然而上面的算法特点是逐一遍历,当计算量足够大时该算法的效率愈显低下,这就迫使我们寻找更高效的算法。。。。。。

思考:如果能够根据已经计算好的丑数,计算出下一个丑数就可以避免这种情况,实现从丑数到丑数的高效算法,根据定义可知,后面的丑数肯定是前面已知丑数乘以2,3,5得到的。

我们假设一个数组中已经有若干丑数,并且这些丑数是按顺序排列的,我们把现有的最大丑数记为max,则下一个丑数肯定是前面丑数乘以2,3,5得到的。不妨考虑乘以2得到的情况,我们把数组中的每一个数都乘以2,由于原数组是有序的,因为乘以2后也是有序递增的,这样必然存在一个数M2,它前面的每一个数都是小于等于max,而包括M2在内的后面的数都是大于max的,因为我们还是要保持递增顺序,所以我们取第一个大于max的数M2。同理对于乘以3的情况,可以取第一个大于max的数M3,对于乘以5的情况,可以取第一个大于max的数M5。

  最终下一个丑数取:min{M2,M3,M5}即可

  代码如下:
  

#include<stdio.h>
int getuglynum(int index);
int main()
{
    int index;
    int count = 0;
    printf("请输入你要找的第几个丑数(其中1为第一个丑数):\n");
    scanf("%d",&index);
    count = getuglynum(index); 
    printf("%d",count);
    return 0;
}
int Min(int num1,int num2,int num3)
{
    //printf("%d %d %d\n",num1,num2,num3);
    int min = (num1 < num2)? num1 : num2;
    min = (min < num3) ? min : num3;
    return min;
}

int getuglynum(int index)
{
    int *data = new int[index];
    data[0] = 1;
    int *data2 = data;
    int *data3 = data;
    int *data5 = data;
    int count = 1;
    int min = 0;
    while(count < index){
        min = Min(*data2 *2,*data3 *3,*data5 *5);
        data[count] = min;
        while(*data2 * 2 <= data[count]){
            ++data2;
        }
            while(*data3 * 3 <= data[count]){
            ++data3;
        }
                while(*data5 * 5 <= data[count]){
            ++data5;
        }
        ++count;
    }
    return data[count-1];
}

 第二种方法由于不需要在非丑数的整数花费时间,因而时间复杂度要小很多,在C-Free+win7的平台上,index=1500时,方法1的运行时间为40s,方法2的时间是1s;然而方法2需要动态分配内存,占用空间,而方法1则没有这样的内存开销。说白了,第二种方法是用空间换时间。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值