寻找第1500个丑数

转自:http://blog.sina.com.cn/s/blog_9dfc6f5f01015nu7.html

诺西笔试最后一道题,题意:

把只包含质因子2、3和5的数称作丑数(Ugly Number),例如:2,3,4,5,6,8,9,10,12,15,等,习惯上我们把1当做是第一个丑数。
写一个高效算法,返回第n个丑数。

最普通(也最耗时)的做法是从1开始遍历,然后判断这个数的因式分解中只包含2,3,5,满足则找到了一个,一直找下去,直到第n个被找出!测试了一下,找第1500个丑数耗时40秒!

分析:假设数组ugly[N]中存放不断产生的丑数,初始只有一个丑数ugly[0]=1,由此出发,下一个丑数由因子2,3,5竞争产生,得到ugly[0]*2, ugly[0]*3, ugly[0]*5, 显然最小的那个数是新的丑数,所以第2个丑数为ugly[1]=2,开始新一轮的竞争,由于上一轮竞争中,因子2获胜,这时因子2应该乘以ugly[1]才显得公平,得到ugly[1]*2,ugly[0]*3,ugly[0]*5, 因子3获胜,ugly[2]=3,同理,下次竞争时因子3应该乘以ugly[1],即:ugly[1]*2, ugly[1]*3, ugly[0]*5, 因子5获胜,得到ugly[3]=5,重复这个过程,直到第n个丑数产生。总之:每次竞争中有一个(也可能是两个)因子胜出,下一次竞争中 胜出的因子就应该加大惩罚!

程序如下所示(只要把程序中的因子改一下就可以得到新的题目),耗时忽略不计:
运行结果:第1500个丑数:859963392, 第1691个丑数2 125 764 000,第1692个丑数就越界了。
int表示的最大整数是2,147,483,647,可由std::cout<<(std::numeric_limits<int>::max)()<<"\n";给出!
[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. int mymin(int a, int b, int c)  
  5. {  
  6.     int temp = (a < b ? a : b);  
  7.     return (temp < c ? temp : c);  
  8. }  
  9. int FindUgly(int n) //  
  10. {  
  11.     int* ugly = new int[n];  
  12.     ugly[0] = 1;  
  13.     int index2 = 0;  
  14.     int index3 = 0;  
  15.     int index5 = 0;  
  16.     int index = 1;  
  17.     while (index < n)  
  18.     {  
  19.         int val = mymin(ugly[index2]*2, ugly[index3]*3, ugly[index5]*5); //竞争产生下一个丑数  
  20.         if (val == ugly[index2]*2) //将产生这个丑数的index*向后挪一位;  
  21.             ++index2;  
  22.         if (val == ugly[index3]*3) //这里不能用elseif,因为可能有两个最小值,这时都要挪动;  
  23.             ++index3;  
  24.         if (val == ugly[index5]*5)  
  25.             ++index5;  
  26.         ugly[index++] = val;  
  27.     }  
  28.   
  29.     int result = ugly[n-1];  
  30.     delete[] ugly;  
  31.     return result;  
  32. }  
  33.   
  34. int main()  
  35. {  
  36.     int num=1;  
  37.     printf("input the number: \n");  
  38.     scanf("%d", &num);  
  39.     printf("%d \n",FindUgly(num));  
  40.     return 0;  
  41. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值