【剑指offer】49 - 丑数

题目描述
  • 题目:我们把只包含因子 2、3 和 5 的数称为丑数(Ugly Number)。求按从小到大的顺序的第 1500 个丑数。例如 6、8 都是丑数,但是 14 不是,因为它包含因子 7。习惯上我们把 1 当做第一个丑数
解题思路
  • 根据丑数定义我们可以知道:丑数可以被 2、3、5整除,即如果一个数可以被 2 整除,那我们对一个数依次循环做 mod(2)运算,若得到最终结果为 1 ,则说明这个数是丑数,同理可被 3、5 整除,我们也是对其循环做 mod(3)运算,mod(5)运算,根据最终结果是否为 1 来判断它是不是丑数
  • 若我们已经可以判断一个数是否是丑数,则只需要从 1 开始依次对每个数进行判断,直到找到第 1500 个丑数为止,此时这个丑数一定是按从小到大顺序的第1500个丑数
  • 这个思路非常直观,也非常简单,代码也很简洁,但是很显然这是一个效率比较低的算法,我们对每个数都要做除运算和模运算,即使这个数不是丑数。这个代码对于小一点的数效率无多大的影响,但是若这个数特别大呢,如果是 10000,100000,或者是更大,显然这个算法就不能满足效率的要求了
  • 所以我们的想法是不要再非丑数的数上花时间。根据丑数的定义,我们可以想到的是:一个丑数可以由另一个丑数乘以 2、3、5 获得。因此我们可以创建一个数组,里面的数是排好序的丑数。但是我们如何我们获取到的丑数是有序的呢 ?
  • 假设数组中已经有若干个排好序的丑数,并且最大的那个记为 M ,下一个丑数肯定是前面已经生成的丑数乘以 2、3、5得到的,这样我们首先考虑给前面每个数乘以 2,若小于 M,则这个丑数肯定已经存在于数组中了,大于 M 的第一个数我们将其记为 M2,同时类似得到 M3,M5,这样 M2,M3,M5中最小的一个即是下一个丑数
  • 事实上我们不需要给已经排好序的所有丑数乘以 2,因为在乘以 2 的过程中会有一个丑数T2,在它之前的每一个丑数乘以 2 都小于 M,我们只需要更新这个 T2 即可,同样的也有 T3,T5.
  • 显然,这个算法虽然有空间的耗费,但是时间效率却有所提高,是一种以空间换时间的算法
  • 思路理清楚后,我们就可以分别来实现这两个算法了
代码实现
  • 思路一
//判断一个数是否是丑数
bool IsUglyNumber(int number)
{
    while(number % 2 == 0)
        num /= 2;
    while(number % 3 == 0)
        num /= 3;
    while(number % 5 == 0)
        num /= 5;
    return number == 1 ? true : false;
}

int GetUglyNumber(int index)
{
    if(index <= 0)
        return 0;
    int number = 0;
    //记录丑数的个数
    int uglynumber = 0;
    while(uglynumber < index)
    {
        ++number;
        if(IsUglyNUmber(number))
            ++uglynumber;
    }
    return number;
}
  • 解法二:
int Min(int num1, int num2, int num3)
{
    int min = num1 < num2 ? num1 : num2;
    min = min < num3 ? min : num3;
    return min;
}

int GetUglyNumber_Solution(int index) 
{
    if (index <= 0)
        return 0;

    int* pUglyNumbers = new int[index];
    pUglyNumbers[0] = 1;

    int nextUglyIndex = 1;

    int *p2 = pUglyNumbers;
    int *p3 = pUglyNumbers;
    int *p5 = pUglyNumbers;

    while (nextUglyIndex < index)
    {
        int min = Min(*p2 * 2, *p3 * 3, *p5 * 5);
        pUglyNumbers[nextUglyIndex] = min;

        //T2
        while (*p2 * 2 <= pUglyNumbers[nextUglyIndex])
            ++p2;
        //T3
        while (*p3 * 3 <= pUglyNumbers[nextUglyIndex])
            ++p3;
        //T5
        while (*p5 * 5 <= pUglyNumbers[nextUglyIndex])
            ++p5;

        ++nextUglyIndex;
    }

    int ugly = pUglyNumbers[nextUglyIndex - 1];
    delete[] pUglyNumbers;
    return ugly;
}

猜你喜欢

转载自blog.csdn.net/Aurora_pole/article/details/81546065