剑指 Offer 49. 丑数 - 力扣(LeetCode)

剑指 Offer 49. 丑数 - 力扣(LeetCode)

题目描述

找出第n个质因数只有2,3,5的数,n<2000

解题思路

方法一:动态规划

考虑第n个数,它必定是由前n-1个数中的某个数乘以2或3或5得到的。假设第一个乘以2大于第n-1个数的数为a,同理可得到b和c,则第n个丑数是由这三个数中乘以对应值后的最小值。这时,另外两个数乘以对应值还是要大于第n个数,而被选中的那个数应该加一右移(应该注意可能存在多个数相等的情况,这时相等的数都需要右移,这样才能保证大于第n个数)。因此可以使用动态规划:

int nthUglyNumber(int n) {
        int a=0,b=0,c=0;
        vector<int> v;
        v.push_back(1);
        for (int i=1;i<n;i++)
        {
            int minn=min(2*v[a],min(3*v[b],5*v[c]));
            if (minn==2*v[a])
                a++;
            if (minn==3*v[b])  //不能用else if,因为可能相等
                b++;
            if (minn==5*v[c])
                c++;
            v.push_back(minn);
        }
        for (int i=0;i<v.size();i++)
            cout<<v[i]<<' ';
        return v[v.size()-1];
    }

时间复杂度:O(n)
空间复杂度:O(n)


方法二

利用最小堆,开始时将1加入堆中,然后每次取出堆中最小的元素,将其分别乘以2,3,5,然后将他们放入堆中,第k次取出的元素即第k大的数。但是可能将重复的元素加入堆中,因此需要利用set先去重。

int nthUglyNumber(int n) {
        priority_queue<ll,vector<ll>,greater<ll> > q;
        set<ll> s;
        s.insert(1);
        q.push(1);
        for (int i=0;i<n;i++)
        {
            ll k=q.top();
            if (i==n-1)
                return k;
            q.pop();
            if (!s.count(2*k))
            {
                q.push(2*k);
                s.insert(2*k);
            }
            if (!s.count(3*k))
            {
                q.push(3*k);
                s.insert(3*k);
            }
            if (!s.count(5*k))
            {
                q.push(5*k);
                s.insert(5*k);
            }
            //cout<<k<<endl;
        }
        return 1;
    }

时间复杂度:O(nlgn)
空间复杂度:O(n)

posted @ 2022-10-23 20:30  sjwsjwsjwsjw1234  阅读(55)  评论(0)    收藏  举报