zoukankan      html  css  js  c++  java
  • Leetcode 丑数

    LC 264. 丑数 II

    题目:你一个整数 n ,请你找出并返回第 n 个 丑数 。丑数 就是只包含质因数 2、3 和/或 5 的正整数。
    方法:介绍三种方法,从最直观的开始

    方法一:堆+欧拉筛

    每次从堆中取一个最小的,然后分别乘2,3,5进行扩展。每次取出的最小值加入答案,需要去重。
    有大量的重复,需要欧拉筛优化才能过

    class Solution {
    public:
        typedef long long ll;
        int nthUglyNumber(int n) {
            vector<ll>primes = {2, 3, 5};
            priority_queue<ll, vector<ll>, greater<ll>>pq;
            pq.push(1);
            set<ll>res;
            while(res.size() < n) {
                ll p = pq.top();pq.pop();
                res.insert(p);
                for(int prime : primes) {
                    pq.push(prime * p);
                    if(p % prime == 0)  break;  // 必需的优化,欧拉筛,p是由prime扩展来的
                }
            }
            return *(--res.end());  // 集合中的最后一个
        }
    };
    

    方法二:二分

    考虑第i个元素是如何生成的,肯定是从已经生成的元素中找到一个值,其乘以2/3/5的值大于且最接近第i-1个。
    对于2,我们可以从第一个开始枚举,直到超过第i-1元素,3、5同理;
    然后取三者的最小值
    由于已生成的数组是有序的,因此可以二分查找

    class Solution {
    public:
        int nthUglyNumber(int n) {
            vector<int>dp;
            dp.push_back(1);
            for(int i = 1;i < n;i++) {
                int a = *upper_bound(dp.begin(), dp.end(), dp[dp.size()-1]/2) * 2;
                int b = *upper_bound(dp.begin(), dp.end(), dp[dp.size()-1]/3) * 3;
                int c = *upper_bound(dp.begin(), dp.end(), dp[dp.size()-1]/5) * 5;
                dp.push_back(min(a, min(b, c)));
            }
            return dp[n-1];
        }
    };
    

    方法三:三指针

    我们从方法二中得到启发,可以发现,二分查找到的点总是往右移的,且如果未采用这个点的值说明该点还未被使用,点不用右移;使用的就右移一位。

    class Solution {
    public:
        int nthUglyNumber(int n) {
            int i2 = 0, i3 = 0, i5 = 0;
            vector<int>dp(n, 0);
            dp[0] = 1;
            for(int i = 1;i < n;i++) {
                dp[i] = min(dp[i2]*2, min(dp[i3]*3, dp[i5]*5));
                if(dp[i] == dp[i2]*2)  i2++;
                if(dp[i] == dp[i3]*3) i3++;  // 不能用else if,为了去重
                if(dp[i] == dp[i5]*5) i5++;
            }
            return dp[n-1];
        }
    };
    

    LC 313. 超级丑数

    题目:与上题相比,不只2,3,4,而是由一个primes数组

    方法:堆+欧拉筛

    class Solution {
    public:
        typedef long long ll;
        int nthSuperUglyNumber(int n, vector<int>& primes) {
            priority_queue<ll, vector<ll>, greater<ll>>pq;
            pq.push(1);
            set<ll>res;
            while(res.size() < n) {
                ll p = pq.top();pq.pop();
                res.insert(p);
                for(int prime : primes) {
                    pq.push(prime * p);
                    if(p % prime == 0)  break;  // 欧拉筛,p是由prime扩展来的
                }
            }
    
            return *(--res.end());  // 集合中的最后一个
        }
    };
    

    当然,也可以使用上面两种方法。

    个性签名:时间会解决一切
  • 相关阅读:
    [core java学习笔记][第五章继承]
    [core java学习笔记][第四章对象与类]
    【转载】Maven中的BOM概念
    【转载】关于docker某些有用的文章
    【转载】linux Jumpserver跳板机堡垒机部署安装使用教程
    四:(之五)Dockerfile语法梳理和实践
    四:FAQ附录(容器交互,镜像交互,镜像导出)
    四:(之四)基于已有镜像构建自己的Docker镜像
    四:(之三)制作镜像和一些docker命令
    四:(之一和之二) docker架构和底层技术分析(C/S架构)
  • 原文地址:https://www.cnblogs.com/lfri/p/15792546.html
Copyright © 2011-2022 走看看