您的位置:首页 > 其它

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

2016-03-20 12:42 344 查看
题目:我们把只包含因子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则没有这样的内存开销。说白了,第二种方法是用空间换时间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: