输出从小到大第n个丑数-空间换时间

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

常规方案:逐个判断每个整数是不是丑数

丑数的定义是只能被2,3,5整除,所以一个整数如果能被2整除,就连续除以2;能被3整除,就连续除以3;能被5整除,就连续除以5。如果最后得到的是1,那么这个数就是丑数。

根据以上思路,我们得到了一个常规解法:

def isUgly(number):
    while(number%2==0):
        number/=2
    while(number%3==0):
        number/=3
    while(number%5==0):
        number/=5
    return [False,True][number==1]

def getUglyNumber1(index):
    if index<0:
        return 0
    number=0
    uglyfound=0
    while(uglyfound<index):
        number+=1
        if isUgly(number):
            uglyfound+=1
    return number

常规解法比较容易理解,但是需要每一个整数都参与判断是否为丑数,大大增加了时间消耗,我们可以对以上解法进行优化,通过一定的空间消耗来换取时间效率,也就是建立一个数组存放从小到大的每一个丑数,循环得到的直接就是丑数。

空间换时间方案:建立丑数数组

根据丑数的定义,一个丑数只包含2,3,5的因子,所以当我们有了一些按顺序排列较小的丑数的时候,并且这些丑数中最大的记为m,分别把这些丑数乘以2,3,5,得到的最小的大于m的值即为要加入丑数数组的下一个值。因为丑数数组已经排序,所以我们可以在循环中更新需要计算乘以2,或者3,或者5的丑数的位置,直到找到题目所求的丑数。

代码如下:

def getUglyNumber2(index):
    if index<0:
        return 0
    pUglyNumbers=[1]*index
    nextUglyIndex=1
    pMultiply2=0
    pMultiply3 = 0
    pMultiply5 = 0

    while(nextUglyIndex<index):
        minn=min(pUglyNumbers[pMultiply2]*2,pUglyNumbers[pMultiply3]*3,pUglyNumbers[pMultiply5]*5)
        pUglyNumbers[nextUglyIndex]=minn
        while(pUglyNumbers[pMultiply2]*2<=pUglyNumbers[nextUglyIndex]):
            pMultiply2+=1
        while (pUglyNumbers[pMultiply3] * 3 <= pUglyNumbers[nextUglyIndex]):
            pMultiply3 += 1
        while (pUglyNumbers[pMultiply5] * 5 <= pUglyNumbers[nextUglyIndex]):
            pMultiply5 += 1
        nextUglyIndex+=1
    return minn

当指定取第1500个丑数时候,两种方法的时间消耗对比如下:

 

当然方法2如果用C或者C++的话,pMutiply2,pMutiply3,pMutiply5的指标可以用指针来实现。

int Min(int number1, int number2, int number3);

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

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

    int *pMultiply2 = pUglyNumbers;
    int *pMultiply3 = pUglyNumbers;
    int *pMultiply5 = pUglyNumbers;

    while(nextUglyIndex < index)
    {
        int min = Min(*pMultiply2 * 2, *pMultiply3 * 3, *pMultiply5 * 5);
        pUglyNumbers[nextUglyIndex] = min;

        while(*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex])
            ++pMultiply2;
        while(*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex])
            ++pMultiply3;
        while(*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex])
            ++pMultiply5;

        ++nextUglyIndex;
    }

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

int Min(int number1, int number2, int number3)
{
    int min = (number1 < number2) ? number1 : number2;
    min = (min < number3) ? min : number3;

    return min;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Briwisdom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值