寻找丑数

最近一直在准备面试,因为要实习了,然后我就纠结了,不知道自己到底处在一个什么样的水平,到底应该选择怎样的实习单位。但是,不管怎么样,还是多看看题吧,感觉面试题还是挺好玩的。最近又在看《编程之美》,感觉有些收获,其实编程真的可以很美,呵呵。

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

      看过《编程之美》的人,应该都知道书上的解题思路,它总是先从最容易想到的解决方法入手,然后再一直追问,有没有更好的解决方法。我觉得这个解决问题的思路非常好,任何问题都要一遍一遍的推敲,找到最佳的解决方案,从空间和时间上进行双重的优化。

    这道题最简单的思路,就是穷举,穷举所有满足条件的数字。其实,仔细想想,穷举有时可以看成是万能的方法,但是效率也是最低的。

 

 

01 bool IsUgly(int number)

02 {

03     while(number % 2 == 0)

04         number /= 2;

05     while(number % 3 == 0)

06         number /= 3;

07     while(number % 5 == 0)

08         number /= 5;

09     return (number == 1) ? true : false;

10 }

11  

12 int Method1(int index)

13 {

14     if(index <= 0)

15         return 0;

16   

17     int number = 0;

18     int uglyFound = 0;

19     while(uglyFound < index)

20     {

21         ++number;

22   

23         if(IsUgly(number))

24         {

25             ++uglyFound;

26         }

27     }

28   

29     return number;

30 }

 

 

       上面的方法,效率低的无法让人接受。于是,我们在寻求更好的解决办法。仔细阅读题目,会发现这题貌似有点像找素数的问题,对了,就是这样,我们换个思路,不是去枚举所有符合条件的数,而是去通过条件生成这些数字。根据丑数的定义,丑数应该是另一个丑数乘以2、3或者5的结果(1除外)。因此我们可以创建一个数组,里面的数字是排好序的丑数。里面的每一个丑数是前面的丑数乘以2、3或者5得到的。这个思路的关键点,就是要保证数组里面的丑数是排好序的。假设 arr[1..i]是已经排好序的数组,则arr[i]一定是这里面最大的数,那么我们只要去寻找新生成的数字中比arr[i]大的的最小的数。新生成的数是由前面的数字*2或*3或*5得到的。我们定义index2为前面数字*2中的所有数字中满足大于arr[i]的最小的数的下标,index3,index5类似定义,则应该放在arr[i+1]位置的数字便是 min(arr[index2]*2,arr[index3]*3,arr[index5]*5)。

注意代码里,index2,index3,index5是维持动态向前的,不会产生无效搜索,因为当前找的数字一定比原来找的要大,所以从上一次找到的下标开始进行搜索就可以了。

具体代码实现如下:

 

 

01 int Min(int a, int b , int c)

02 {

03     a=a<b?a:b;

04     if(c<a) return c;

05     else return a;

06 }

07  

08 int Method2(int Mindex)

09 {

10     int index=1;

11     int *arr= new int[Mindex];

12     arr[0]=1;

13     int index2=0, index3=0, index5=0;

14     while(index<Mindex)

15     {

16         int min=Min(arr[index2]*2,arr[index3]*3,arr[index5]*5);

17         arr[index]=min;

18         while(arr[index2]*2<=arr[index]) index2++;

19         while(arr[index3]*3<=arr[index]) index3++;

20         while(arr[index5]*5<=arr[index]) index5++;

21         index++;

22     }

 

 

 

 

1 int ans=arr[Mindex-1];

 

 

 

 

1    delete arr;

2     return ans;

3 }

原帖地址:http://www.cnblogs.com/coser/archive/2011/03/07/1976525.html

《编程之美》:豆瓣 微博

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值