leetcode 丑数系列 丑数1/2 超级丑数 (263、264、313 质因数的应用 多指针动态规划)

263 丑数

题目描述: 编写一个程序判断给定的数是否为丑数。丑数就是只包含质因数 2, 3, 5 的正整数。
思路: 此题较为简单,想要判断一个数的因子是否为2,3,5只需要判断对这个几个数进行取模然后再除以这几个数,直到最后为1即是丑数。如果对这个几个数取模都不能整除那一定不是丑数,所以使用else if,一直连续判断,如果除以2,3,5,都除不尽那就是丑数。

class Solution {
public:
    bool isUgly(int num) {
        if(num <= 0)
            return false;
        while(num % 2 == 0)
            num = num / 2;
        while(num % 3 == 0)
            num = num / 3;
        while(num % 5 == 0)
            num = num / 5;
        if(num == 1)
            return true;
        return false;
    }
};

264 丑数2

题目描述: 编写一个程序,找出第 n 个丑数。丑数就是只包含质因数 2, 3, 5 的正整数。
示例: 输入: n = 10;输出: 12;解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明: 1 是丑数。n 不超过1690。
思路1(超时): 从1开始,判断每一个数是不是丑数,如果是 ,计数器加一,当计数器等于n时,返回当前的数。
思路2(优先队列)(慢): 定义一个实现小顶堆的优先队列,首先将1push进该队列,之后对每个从队列中pop出的数分别乘以2/3/5并压进队列。第n个pop出的数即为所求。
思路3(动态规划)(快): 三指针动态规划。首先创建一维动态规划数组,dp[i]表示第i个丑数的值。我们设3个指针index2、index3、index5,代表的是第几个数的2倍、第几个数3倍、第几个数5倍。动态规划方程dp[i]=min(dp[p_2]*2,dp[p_3]*3,dp[p_5]*5)。具体思路见代码中注释。

// 思路2 优先队列
class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> tmp(3,0);
        tmp[0] = 2, tmp[1] = 3, tmp[2] = 5;
        priority_queue <int,vector<int>,greater<int> > Q;
        unordered_map<int, int> mp;
        Q.push(1);
        mp[1] = 1;
        int cnt  = 0;
        int int_max = (1LL << 31) - 1;
        while(!Q.empty()) {
            int q = Q.top();
            // cout << q << endl;
            cnt++;
            if(cnt == n)
                return q;
            Q.pop();
            for(int i = 0; i < tmp.size(); i++) {
                if(1LL * q * tmp[i] >= int_max)
                    continue;
                if(mp[q * tmp[i]] == 0) {
                    Q.push(q * tmp[i]);
                    mp[q * tmp[i]] = 1;
                }
            }
        }
        return 1;
    }
};
// 思路3 动态规划
class Solution {
public:
    // 一维动态规划 记录index2/index3/index5。即最小的未用的乘以2的丑数的位置、乘以3的丑数的位置、乘以5的丑数位置。
    int threeNumMin(int a, int b, int c) {
        int tmp = min(a, b);
        return min(tmp, c);
    }
    int nthUglyNumber(int n) {
        vector<int> dp(n + 1, 0);
        dp[1] = 1;
        int index2 = 1, index3 = 1, index5 = 1;
        for(int i = 2; i <= n; i++) {
            dp[i] = threeNumMin(dp[index2] * 2, dp[index3] * 3, dp[index5] * 5);
            if(dp[index2] * 2 == dp[i])
                index2++;
            if(dp[index3] * 3 == dp[i])
                index3++;
            if(dp[index5] * 5 == dp[i])
                index5++;
        }
        return dp[n];
    }
};

313 超级丑数

题目描述: 编写一段程序来查找第 n 个超级丑数。超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。
说明: 1 是任何给定 primes 的超级丑数;给定 primes 中的数字以升序排列;
0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000;第 n 个超级丑数确保在 32 位有符整数范围内。
思路: 本题目为264题(丑数2)的泛化版本 相当于将原来的index2/index3/index5封装成一个数组。动态规划或者小顶堆(耗时高)均可做。

// 动态规划解法
class Solution {
public:
    // 本题目为264题(丑数2)的泛化版本 相当于将原来的index2/index3/index5封装成一个数组。
    // 动态规划 或者 小顶堆(耗时高)均可做
    int nthSuperUglyNumber(int n, vector<int>& primes) {
        vector<int> dp(n + 1, 0);
        dp[1] = 1;
        vector<int> index(primes.size(), 1);
        for(int i = 2; i <= n; i++) {
            int minNum = INT_MAX;
            for(int j = 0; j < primes.size(); j++) // 求最小值
                minNum = min(minNum, dp[index[j]] * primes[j]);
            for(int j = 0; j < primes.size(); j++) { // 将本次用到的素数的index加一
                if(minNum == dp[index[j]] * primes[j])
                    index[j]++;
            }
            dp[i] = minNum;   
        }
        return dp[n];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值