【剑指offer】面试题34-丑数

问题描述:

我们把只包含因子2,3,5的数称为丑数,求按照从小到大的顺序的第1500个丑数。例如6,8都是丑数,但14不是,因为14含有因子7.我们习惯上把1当做第一个丑数。


问题分析:

方法1:从1开始,对每一个数都进行判断,看是否只含有2,3,5的因子,直到找到第1500个丑数为止。这种方法理解起来比较容易,但是却做了很多无用功,比如,对于非丑数,都进行了模除模除的操作,所以,时间上是比较浪费的。
方法2:鉴于以上的方法需要花费很多的时间在非丑数上,这种办法采用空间换取时间,任何一个丑数都是由前边一个比他小的丑数计算得来的,也就是说丑数肯定是由丑数产生的。
具体方法:我们创建一个1500的数组,里边存储已经排好序的丑数。里边的每一个丑数都是由前边的一个丑数乘以2或者3或者得到的,当前数组中的最后一个数一定是数组中最大的一个丑数。我们定义3个指针,初始化执行数组的第一个元素,让对应的数分别乘以2,乘以3,乘以5,得到3个数,取出3个数的最小的一个,一定是下一个丑数,并存储在数组中。每次都从前边的数字计算出一个丑数(三个指针指向的数分别乘以2,3,5),如果小于数组中最后一个丑数,对应的指针向后移动。找到第1500个丑数,然后输出即可。大致思路就是这样。
方法3:利用关联容器set。由于set中存储不重复的key,并且还会升序排列,利用这一特性,可以求出丑数。对于set不是很清楚的读者,戳进去http://blog.csdn.net/peiyao456/article/details/53161390


代码实现:

方法1这样的方法实现起来比较容易,并且在面试中一般不会得到面试官的喜爱,所以这里只给出后2中方法的实现。


方法2:

#include<iostream>
using namespace std;
int Min(int x,int y,int z)
{
    int min = (x < y)?x : y;
    return min < z ? min : z;
}
int GetUglyNumber(int index)
{
    if(index <= 0)
       return 0;
    int* pUglyNumbers = new int[index];
    pUglyNumbers[0] = 1;
    int NextUglyNumbers = 1;
    int* pUgly2 = pUglyNumbers;
    int* pUgly3 = pUglyNumbers;
    int* pUgly5 = pUglyNumbers;
    while(NextUglyNumbers < index)
    {
       int min = Min(*pUgly2*2,*pUgly3*3,*pUgly5*5);
       pUglyNumbers[NextUglyNumbers++] = min;
       while(*pUgly2 * 2 <= min)
           pUgly2++;
       while(*pUgly3 * 3 <= min)
           pUgly3++;
       while(*pUgly5 * 5 <= min)
           pUgly5++;
    }
    int ugly = pUglyNumbers[index - 1];
    delete[] pUglyNumbers;
    return ugly;
}
int main()
{
    int index = 0;
    cin>>index;
    cout<<GetUglyNumber(index)<<endl;
    system("pause");
    return 0;
}

方法3:

#include<iostream>
using namespace std;
#include<limits.h>
#include<set>
int GetUglyNumber(int index)
{
    if(index <= 0)
       return 0;
    set<int,less<int>> s;
    set<int,less<int>>::iterator it;
    s.insert(1);
    for(int i = 1; i < index * 6 /*INT_MAX/5*/; ++i)
    {
       s.insert(i * 2);
       s.insert(i * 3);
       s.insert(i * 5);
    }
    int i = 0;
    for(it = s.begin(),i = 1; it != s.end()&&i < index; ++it,++i)
    {}
    cout<<*it<<endl;
}
int main()
{
    int index = 0;
    cin>>index;
    GetUglyNumber(index);
    system("pause");
    return 0;
}

方法3中,向set中插入数据,i的范围究竟是多少?去参考http://blog.csdn.net/coder_xia/article/details/6707600他给出的是INT_MAX/5,原因是防止丑数超出了整数的最大值。我按照这样的方法去试了一下,程序运行的时间比较久(具体多长时间我没有测试),我给出的是index*6,也就是需要的丑数序列的6倍,为什么我要乘一个数呢?(其实不乘也是可以正确求出第1500个丑数的)但是还是害怕数据有过多的重复(15 == 3 * 5,是丑数,i == 3时,会计算出15,i==5时,也是会计算出15),所以这里乘了一个因数。


关于这道题目还有几种方法,上述链接的作者果然厉害~~感兴趣的可以自行去查看。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值