寻找丑数
2012-08-27 11:08
246 查看
原文:/article/5255308.html
题目:我们把只包含因子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,则该数是素数,否则是丑数。
代码如下:
上面计算中主要的不足在于,逐一遍历,这样对于不是丑数的数的判断会造成大量的时间浪费,如果能够根据已经计算好的丑数,计算出下一个丑数就可以避免这种情况,实现从丑数到丑数的高效算法,根据定义可知,后面的丑数肯定是前面已知丑数乘以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}即可
代码如下:
第二种方法由于不需要在非丑数的整数花费时间,因而时间复杂度要小很多,在vc6+win7的平台上,index=1500时,方法1的运行时间为40s,方法2的时间是1s;然而方法2需要动态分配内存,占用空间,而方法2则没有这样的内存开销。说白了,第二种方法是用空间换时间。
题目:我们把只包含因子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,则该数是素数,否则是丑数。
代码如下:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 //判断一个给定的数number是否是丑数 6 bool IsUgly(int number) 7 { 8 while(number % 2 == 0) 9 { 10 number /= 2; 11 } 12 while(number % 3 ==0) 13 { 14 number /= 3; 15 } 16 while(number % 5 ==0) 17 { 18 number /= 5; 19 } 20 return(number == 1)?true:false; 21 } 22 23 //返回从1开始第index个丑数 24 int GetUglyNumber(int index) 25 { 26 if(index <= 0) 27 { 28 return 0; 29 } 30 31 int number=0; 32 int count=0; 33 while(count < index) 34 { 35 ++number; 36 if(IsUgly(number)) 37 { 38 ++count; 39 } 40 41 } 42 43 return number; 44 } 45 46 int main() 47 { 48 cout<<"Enter A Number:"<<endl; 49 int idx=0; 50 cin>>idx; 51 cout<<GetUglyNumber(idx)<<endl; 52 return 0; 53 }
上面计算中主要的不足在于,逐一遍历,这样对于不是丑数的数的判断会造成大量的时间浪费,如果能够根据已经计算好的丑数,计算出下一个丑数就可以避免这种情况,实现从丑数到丑数的高效算法,根据定义可知,后面的丑数肯定是前面已知丑数乘以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}即可
代码如下:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 //返回三个数中的最小者 6 int Min(int number1,int number2,int number3) 7 { 8 int min = (number1 < number2) ? number1 : number2; 9 min = (min < number3) ? min : number3; 10 return min; 11 } 12 13 //返回第index个丑数 14 int GetUglyNumber(int index) 15 { 16 if(index <= 0) 17 { 18 return 0; 19 } 20 21 int *pUglyNumbers = new int[index]; 22 pUglyNumbers[0] = 1; 23 int nextUglyIndex = 1; 24 25 int *pMultiply2 = pUglyNumbers; 26 int *pMultiply3 = pUglyNumbers; 27 int *pMultiply5 = pUglyNumbers; 28 29 while(nextUglyIndex < index) 30 { 31 int min = Min(*pMultiply2 * 2,*pMultiply3 * 3,*pMultiply5 * 5); 32 pUglyNumbers[nextUglyIndex] = min; 33 34 while(*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex]) 35 { 36 ++pMultiply2; 37 } 38 while(*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex]) 39 { 40 ++pMultiply3; 41 } 42 while(*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex]) 43 { 44 ++pMultiply5; 45 } 46 47 ++nextUglyIndex; 48 } 49 50 int ugly = pUglyNumbers[nextUglyIndex-1]; 51 delete[] pUglyNumbers; 52 return ugly; 53 54 } 55 56 int main() 57 { 58 cout<<"Enter A number:"<<endl; 59 int number=0; 60 cin>>number; 61 cout<<GetUglyNumber(number)<<endl; 62 return 0; 63 }
第二种方法由于不需要在非丑数的整数花费时间,因而时间复杂度要小很多,在vc6+win7的平台上,index=1500时,方法1的运行时间为40s,方法2的时间是1s;然而方法2需要动态分配内存,占用空间,而方法2则没有这样的内存开销。说白了,第二种方法是用空间换时间。
相关文章推荐
- 寻找丑数
- (剑指offer)丑数 寻找第一个只出现一次的字符
- 寻找丑数
- 寻找丑数(Ugly Number)
- 寻找丑数及关于程序优化效率的一点说明
- 算法学习笔记之寻找第1500个丑数
- 算法习题64:寻找丑数2 3 5的倍数
- 九度OJ 1214 寻找丑数【算法】
- 每日一道算法题-寻找丑数
- 寻找丑数
- 剑指offer系列之三十二:寻找丑数
- 264.leetcode Ugly Number II(medium)[寻找第N个丑数]
- 九度OJ 1214 寻找丑数【算法】
- 每日一道算法题-寻找丑数
- 寻找丑数
- 寻找丑数,把只包含因子2、3和5的数称作丑数(Ugly Number)
- 2081 寻找丑数
- Ugly Number 寻找丑数 简单题
- 算法题3 寻找丑数&数值逼近
- 【算法01】寻找丑数