264. Ugly Number II

仅供自己学习

思路:

暴力

刚开始看确实没思路,用的暴力法。因为他要的数是质因数只为2,3,5的。那么我们只需要获得通过2,3,5相乘得到的数即可。通过三个循环,先a=a2,然后b=a,b=b3,最后c=b,c=c5,这样得到的c就是是由23*5得到的数,但是这样得到的数,没法确定大小关系,所以还需要一个数组存入排序后,才能获得第n个丑数
a,b,c得用longlong,不然会溢出

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> res;
        for(long long a = 1;a<=INT_MAX;a=a*2){
            for(long long b=a;b<=INT_MAX;b=b*3){
                for(long long c=b;c<=INT_MAX;c=c*5){
                    res.push_back(c);
                }
            }
        }
        sort(res.begin(),res.end());
        return res[n-1]
    }
};

小顶堆

因为我们需要升序第n个数,而且暴力做法有个问题就是没法确定大小关系,那么我们通过堆的数据结构,每次都能保证取到当前最小的数来获取新的较小的丑数。那么我们只需要循环n-1次就可以得到这个丑数,因为1默认为丑数,所以用n-1。但是这里还有个问题就是重复的问题,对于12,有2和6,4和3 两种情况,而这两种都是满足丑数,所以我们还需要把重复的元素删掉,因为我们每次都会获取堆顶元素,并弹出,如果有重复的那么堆顶的元素会等于取出来的元素,通过这个条件可以去掉相同元素。
代码:

class Solution {
public:
    int nthUglyNumber(int n) {
        priority_queue <double,vector<double>,greater<double>> pq;
        double answer=1;
        for(int i=1;i<n;i++){
            pq.push(answer*2);
            pq.push(answer*3);
            pq.push(answer*5);
            answer=pq.top();
            pq.pop();
            while(!pq.empty()&&answer==pq.top()) pq.pop();        
        }
        
        return answer;
        
    }
};

因为set数据结构能也能自动排序且能自动去重,那么可以直接用set存放即可。

class Solution {
public:
    int nthUglyNumber(int n) {
        set<double> st;
        double answer=1;
        for(int i=1;i<n;i++){
            st.insert(answer*2);
            st.insert(answer*3);
            st.insert(answer*5);
            answer=*st.begin();
            st.erase(answer);
        }
        return answer;
        
    }
};

动态规划(三指针)

我们定义三个指针p2,p3,p4,并初始化为0,我们每次判断2dp[p2],3dp[p3],5dp[p5]谁更小,并将最小的赋给dp[i]相当于我们每次都获取最小的并将最小的值放在数组最前面。和堆不同的地方是,堆先放入数组在排序,动态规划是先排序再放入数组。然后再将赋给dp[i]的指针右移,因为现在的做法会让数组每个数都有2,3,5的数满足丑数,所以直接右移即可。
那么我们的放入数组的就是从小到大的排序,直接取第n-1个即可。
代码:

class Solution {
public:
    int nthUglyNumber(int n) {
        int p2=0,p3=0,p5=0;
        vector<int> dp(n);
        dp[0]=1;
        for(int i=1;i<n;++i){
            dp[i] = min(min(2*dp[p2],3*dp[p3]),5*dp[p5]);
            if(dp[i]==2*dp[p2]) p2++;
            if(dp[i]==3*dp[p3]) p3++;
            if(dp[i]==5*dp[p5]) p5++;
        }
        return dp[n-1];
        
    }
};
posted @ 2021-04-07 17:05  Mrsdwang  阅读(32)  评论(0编辑  收藏  举报