Ugly Number II

https://leetcode.com/problems/ugly-number-ii/

第N个丑数,用暴力法导致,从1开始逐个验证是否是丑数,然后一直到找到第N个丑数,这个方法会超时。

因为,当数字增大到一定的情况的时候,每个丑数之间的间隔是以指数倍增加的,导致了遍历的方法会在 i++ 的过程中耗费太多时间。 

另一种解法:
将丑数拆解,由于丑数的是由2 3 5这几个质因子组成的,那么,只需要使用一个动态规划的数组来存放每次计算后得到的新增丑数即可。

从倒数第一个数开始,从后往前遍历,对其*2,*3,*5。并且,如果其结果大于倒数第一个数,则将其记录到对应的last当中。

而可以设置一个循环终止条件是,如果得到的三个last都是小于倒数第一个数的,那么此时可以终止循环,并且在3个last当中选取最小来填补第 i 出的数组值。

而此题的有一个陷阱就是,对于int型的大数,如果其逼近于int表示的正数的极限时,会产生溢出,那么此时,在进行*2,*3,*5运算时,会导致结果为负数。

解决方方案是,对于所有涉及到计算的部分的数字,全部转换为unsigned int 类型之后再进行计算,而后将最终的计算结果以int类型进行返回即可。

class Solution {
public:
    int nthUglyNumber(int n) {
        if(n<=0)
            return 0;
        if(n==1)
            return 1;
        unsigned int * res=new unsigned int[n];
        unsigned int last2=2;
        unsigned int last3=3;
        unsigned int last5=5;
            
        res[0]=1;
        
        for(int i=1;i<n;i++)
        {
            for(int index=i-1;index>=0;index--)
            {
                if(res[index]*2<=res[i-1]&&res[index]*3<=res[i-1]&&res[index]*5<=res[i-1])
                    break;
                if(res[index]*2>res[i-1])
                    last2=res[index]*2;
                if(res[index]*3>res[i-1])
                    last3=res[index]*3;
                if(res[index]*5>res[i-1])
                    last5=res[index]*5;
                //此处注意大数溢出的问题,在循环到1545处的时候的结果是1073741824
                //而在32位的int标是的最大正数是2的31次方-1,所以结果是2147483648
                //此时由于在进行*2 *3 *5等操作时候,超过了正数的表达范围,溢出变负数,所以导致了普适算法中的if比较失效
                //解决方案是,通过将数字统统按照无符号int型来进行计算,之后在换算成int结果返回
                    
            }
            res[i]=getMin(last2,last3,last5);
        }
        return res[n-1];
    }
    int getMin(unsigned int a,unsigned int b,unsigned int c)
    {
        unsigned int min=a<b?a:b;
        min=min<c?min:c;
        
        return min;
    }
    
};

  

原文地址:https://www.cnblogs.com/aguai1992/p/5021946.html