丑数 II

160 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情

给你一个整数 n ,请你找出并返回第 n 个 丑数 。

丑数 就是只包含质因数 2、3 和/或 5 的正整数。

示例 1:

输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。

示例 2:

输入:n = 1 输出:1 解释:1 通常被视为丑数。

提示:

1 <= n <= 1690

解题思路

既然是一道dp题,那么最关键的就是找到前后联系,那甚么联系呢? 显然,新的抽数一定是由之前的丑数*2 *3 5得到的 那么dp数组就应该是从1开始的抽数,当然为了让下标直接表示第几个,可以让dp[0]=0 dp[1]=1 进一步明确联系,dp[n]一定是最接近dp[n-1]的那个丑数,模板思路到此,下一步只能靠经验 这次的dp如果采用倒推,那么就向上面注释的那样,思路简单清晰,但是会超时 所以这次的新dp只能正推,直接用小丑数获取新的大丑数, 从根源上分析,人工如何计算下一个丑数?那肯定是把比较小的几个丑数分别乘2 3 5 比一下,选出最小的 那么这一步最关键, 理解每一个丑数2 *3 5都会产生新的丑数,那就分成三组看待 第一组只从左往右通过2创建新丑数, 第二组第三组同理,那只需要每次只选出最小的即可

public:
    int nthUglyNumber(int n) {
    
        // // 0为非丑 数字为第几个丑
         if( n<=1 ){
            return n;
         }
        vector<int> np(2,0);
         np[1]=1;
        int count=2;
         for(int i=2; i<=5000000; i++){
             //add a vec
             np.push_back(0);

            if( i%2==0 ){
                np[i]=np[ i/2 ]>0?  count++  :0;
            }
             else if( i%3==0 ){
                 np[i]=np[ i/3 ]>0?  count++  :0;
             }
             else if( i%5==0 ){
                 np[i]=np[ i/5 ]>0?  count++  :0;
             }
            
            if( count-1 == n ){
                 return i;
             }
         }
         return -1;

        if(n<=1){
            return n;
        }

        
        vector<int> dp(2,0);
        dp[1]=1;
        int from2=1;
        int from3=1;
        int from5=1;
        // 产生第i个丑数
        for(int i=2 ; i<=n ; i++ ){
            dp.push_back(0);// 保证不越界

            int newUgly = min( dp[from2]*2 ,min( dp[from3]*3,dp[from5]*5 ) ); 
            dp[i]=newUgly;
            if( newUgly > dp[i-1] ){
                dp[i]=newUgly;
            }
            else{
                i--;
            }
            
            //把下面的else 去掉 也可以去重
            if( newUgly == dp[from2]*2){
                from2++;
            }
            else if( newUgly == dp[from3]*3 ){
                from3++;
            }
            else if( newUgly == dp[from5]*5 ){
                from5++;
            }
            
        }
        return dp[n];

    }
};