【LeetCode】丑数题目合辑

news2024/12/23 10:53:36

文章目录

  • 263. 丑数
      • 思路
      • 代码
  • 264. 丑数 II
    • 方法一:最小堆
      • 思路
      • 代码
    • 方法二:动态规划(三指针法)
      • 思路
      • 代码
  • 1201. 丑数 III
    • 方法:二分查找 + 容斥原理
      • 思路
      • 代码
  • 313. 超级丑数
    • 方法:“多路归并”
      • 思路
      • 代码
  • 总结
  • 参考资料

263. 丑数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

  • 首先,丑数必须是正整数,因此对于 n<1 都可以直接返回 false;
  • 对于 n >= 1 ,如果 n 能够被 2/3/5 整除,说明它们是丑数。

代码

class Solution {
public:
    bool isUgly(int n) {
        // ugly只能是正整数
        if(n < 1) return false;
        vector<int> factors = {2, 3, 5};
        for(int i=0; i<=2; ++i){
            while(n % factors[i] == 0){
                n /= factors[i];
            }
        }
        return n == 1;
    }
};

264. 丑数 II

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法一:最小堆

思路

  • 要得到第 n 个丑数,可以使用最小堆实现。
  • 初始化堆为空,首先将最小的丑数 1 加入。每次取出堆顶元素 x ,则 x 是堆中最小的丑数,2x、3x、5x 必然也是丑数,因此将它们也加入最小堆。
  • 但是上述做法会出现重复元素,为了避免这种情况,用哈希集合去重,避免相同元素多次加入堆。
  • 在排除重复元素的情况下,第 n 次从最小堆中取出的元素即为第 n 个丑数。

代码

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> factor = {2, 3, 5};
        priority_queue<long, vector<long>, greater<long>> heap;
        unordered_set<long> s;
        // 先把丑数 1 加入
        s.insert(1L);
        heap.push(1L);
        long cur;
        for(int i=0; i<n; ++i){
            cur = heap.top();
            heap.pop();
            for(int f : factor){
                // 依次计算 2x 3x 5x
                long temp = cur * f;
                // s中没有temp 将其存入
                if(!s.count(temp)){
                    s.insert(temp);
                    heap.push(temp);
                }
            }
        }
        return (int)cur;
    }
};

方法二:动态规划(三指针法)

思路

  • 方法一使用最小堆,会预先存储较多的丑数,维护最小堆的过程也导致时间复杂度较高。可以使用动态规划的方法进行优化。

  • 定义数组 dp,其中 dp[i] 表示第 i 个丑数,则 dp[n] 为这道题的答案。其中,dp[1] = 1。

  • 剩余的丑数我们可以通过三个指针 p2 、p3、p5 计算得到。pi 的含义是有资格同 i 相乘的最小丑数的位置。这里资格指的是:如果一个丑数nums[pi]通过乘以 i 可以得到下一个丑数,那么这个丑数nums[pi]就永远失去了同 i 相乘的资格,我们把pi++,让 nums[pi] 指向下一个丑数即可。

  • 举例说明:

    一开始,丑数只有{1},1 可以同 2,3,5相乘,取最小的 1×2=2 添加到丑数序列中。

    现在丑数中有{1,2},在上一步中,1 已经同 2 相乘过了,所以今后没必要再比较 1×2 了,因此认为 1 失去了同 2 相乘的资格。

    现在 1 有与 3,5 相乘的资格,2 有与 2,3,5 相乘的资格,但是 2×3 和 2×5 肯定比 1×3 和 1×5 大,因此没必要比较。所以我们只需要比较 1×3,1×5,2×2

    依此类推,每次我们都分别比较有资格同 2,3,5 相乘的最小丑数,选择最小的那个作为下一个丑数,假设选择到的这个丑数是同 i(i=2,3,5)相乘得到的,所以它失去了同 i 相乘的资格,把对应的pi++,让 pi 指向下一个丑数即可。

代码

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> dp(n+1);
        dp[1] = 1;
        int p2 = 1, p3 = 1, p5 = 1;
        for(int i=2; i<=n; ++i){
            int num2 = 2 * dp[p2];
            int num3 = 3 * dp[p3];
            int num5 = 5 * dp[p5];
            dp[i] = min(min(num2, num3), num5);
            // 确定dp[i]是由哪个数字生成的
            if(dp[i] == num2)   p2++;
            if(dp[i] == num3)   p3++;
            if(dp[i] == num5)   p5++;
        }
        return dp[n];
    }
};

1201. 丑数 III

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

方法:二分查找 + 容斥原理

思路

  • 首先要注意的是,这道题和前两题对于“丑数”的定义并不相同。这里不能直接枚举丑数 x(三指针法),因为 x 太大了,会导致超时。

  • 这道题是 878. 第 N 个神奇数字 的升级版。把两个数改为了三个数,难度更高。与 878 题相比,这题的只需要修改求小于等于 x 的丑数个数的函数,二分查找部分一模一样。建议先复习 878 题,下面附上该题的思路图。

    在这里插入图片描述

  • 把小于等于 x 的 a 的倍数、b 的倍数、c 的倍数组成的集合分别叫做 A、B、C ,小于等于 x 的丑数相当于集合 A∪B∪C ,集合的元素个数为 ∣A∪B∪C∣,由 容斥原理可得:

    ∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣

  • 因此,小于等于 x 的丑数的个数为:x/a + x/b + x/c - x/lcm_a_b - x/lcm_b_c - x/lcm_a_c + x/lcm_a_b_c 。可以使用最小公倍数函数 std::lcm

  • 接下来通过二分搜索,不断缩小边界,直到某个位置所对应的数恰好包含了 n 个丑数因子为止。

代码

class Solution {
public:
    using ll = long long;
    ll nthUglyNumber(ll n, ll a, ll b, ll c) {
        ll lcm_a_b = std::lcm(a, b), lcm_a_c = std::lcm(a, c), lcm_b_c = std::lcm(b, c);
        ll lcm_a_b_c= std::lcm(lcm_a_b, c);
        // 最小的丑数必然是a、b、c的最小值
        ll left = min(min(a, b), c);
        ll right = n * left;
        while(left + 1 < right){
            ll mid = (left + right) / 2;
            if(mid/a + mid/b + mid/c - mid/lcm_a_b - mid/lcm_a_c - mid/lcm_b_c + mid/lcm_a_b_c < n){
                left = mid;
            }
            else right = mid;
        }
        return right;
    }
};

313. 超级丑数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法:“多路归并”

思路

  • 这道题其实是 264. 丑数 II 的进阶,前者固定使用三个指针,分别对应于 2、3、5,而这道的primes数组长度不固定,因此使用指针数组来对应 primes 的每一个值。

  • 第一个丑数一定是 1,而「往后产生的丑数」都是基于「已有丑数」而来(使用「已有丑数」乘上「给定质因数」primes[i] )。具体过程如图所示。

    在这里插入图片描述

    • 显然,我们需要每次取值最小的一个,然后让指针后移(指向下一个丑数),不断重复这个过程,直到找到第 n 个丑数。
    • 另外,由于我们每个指针移动和 dp的构造,都是单调递增,因此可以通过与 dp[i-1] 进行比较来实现去重,而无须引用 Set 结构。

代码

class Solution {
public:
    long nthSuperUglyNumber(int n, vector<int>& primes) {
        int len = primes.size();
        // 指针数组
        vector<long> ptr(len, 1);
        vector<long> dp(n+1, 0);
        dp[1] = 1;
        for(int i=2;i<=n;++i){
            int flag = 0;
            dp[i] = primes[0] * dp[ptr[0]];
            for(int j=0; j<len; ++j){
                long cur = primes[j] * dp[ptr[j]];
                if(cur < dp[i]){
                    flag = j;
                    dp[i]= cur;
                }     
            }
            ptr[flag]++;
            // 如果当前值和上一个丑数一样,那么跳过该丑数
            if(dp[i] == dp[i-1]) i--;
        
        }
        return dp[n];
    }
};

总结

  • 以上是丑数的所有相关题目,丑数的定义并不固定,因此需要仔细理解题意后再开始计算。
  • 对于 263. 丑数,运用简单的数学思想即可解决;
  • 对于264. 丑数II ,使用了最小堆动态规划(即三指针的方法),但是最小堆的方法比较费时,更推荐方法二;
  • 对于1201. 丑数III ,与一般的丑数定义不同,是 878. 第 N 个神奇数字 的升级版,使用了二分查找容斥原理
  • 对于313.超级丑数 ,是 264. 丑数II 的升级版,将三指针方法扩展为多指针即可求解,也可以理解为多路归并法

参考资料

  1. 丑数 II 官方题解
  2. 三指针方法的理解方式
  3. 313. 超级丑数:【宫水三叶】一题双解 :「优先队列」&「多路归并」

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/857616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何压缩照片?一看就会的压缩方法

压缩照片是再正常不过的需求了&#xff0c;比如上传个证件照&#xff0c;要求在20k以内&#xff0c;那么超过这个大小的照片我们就必须进行压缩处理&#xff0c;其实现在压缩照片的方法也特别多&#xff0c;不论是压缩软件、图片编辑软件&#xff0c;甚至在线网站都能搞定。 下…

SpringBoot 将项目打包成 jar 包

SpringBoot 将项目打包成 jar 包 一、项目打包成 jar 包 首先在 pom.xml 文件中导入 Springboot 的 maven 依赖 <!-- 将应用打包成一个可以执行的 jar 包 --> <build><plugins><plugin><groupId>org.springframework.boot</groupId><…

go-admin 使用开发

在项目中使用redis 作为数据缓存&#xff1a;首先引入该包 “github.com/go-redis/redis/v8” client : redis.NewClient(&redis.Options{Addr: config.QueueConfig.Redis.Addr, // Redis 服务器地址Password: config.QueueConfig.Redis.Password, // Redis 密码&…

【LeetCode 75】第二十五题(735)行星碰撞

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 给一个数组&#xff0c;数组里的元素表示行星&#xff0c;元素的符号决定行星运动的方向&#xff0c;元素的绝对值决定行星的大小…

谷歌发布RT-2大模型,让机器人像人类那样思考

原创 | 文 BFT机器人 大语言模型是指基于深度学习技术的大规模预训练模型&#xff0c;它能够通过学习大量的文本数据来生成人类类似的语言表达&#xff0c;机器人可以通过对大量的语言数据进行学习&#xff0c;从中掌握人类的语言表达方式&#xff0c;进而能够更好地与人进行交…

冠达管理:股票注册制通俗理解?

目前我国A股商场正在进行股票注册制变革&#xff0c;相较之前的发行准则&#xff0c;股票注册制在理念上更为商场化&#xff0c;这意味着公司发行股票的门槛将下降&#xff0c;公司数量将添加&#xff0c;而股票流通的方式也将有所改变。那么股票注册制指的是什么&#xff0c;它…

日常报错记录

日常报错记录 Shorten the command line via JAR manifest or via a classpath file and rerun 解决方法如下&#xff1a;

代码分析:waitpid的使用,非阻塞轮回检测技术

wait 函数 wait函数的作用是父进程调用&#xff0c;等待子进程退出&#xff0c;回收子进程的资源&#xff1b; #include<sys/types.h> #include<sys/wait.h> pid_t wait(int*status);返回值&#xff1a; 成功返回被等待进程pid&#xff0c;失败返回-1。 参数&…

B2B2C小程序商城系统--跨境电商后台数据采集功能开发

搭建一个B2B2C小程序商城系统涉及到多个步骤和功能开发&#xff0c;其中包括跨境电商后台数据采集功能的开发。具体搭建步骤如下&#xff1a; 一、系统搭建 1. 确定需求和功能&#xff1a;根据B2B2C商城的需求&#xff0c;确定系统的功能和模块&#xff0c;包括商品管理、订单…

大数据离线阶段02:Apache Hadoop

Hadoop介绍 Hadoop是Apache旗下的一个用java语言实现开源软件框架&#xff0c;是一个开发和运行处理大规模数据的软件平台。允许使用简单的编程模型在大量计算机集群上对大型数据集进行分布式处理。 狭义上说&#xff0c;Hadoop指Apache这款开源框架&#xff0c;它的核心组件有…

一款用于监控电路监控数字系统中的电源 电压监控器 CAT809STBI-GT3

什么是电压监控器&#xff1f; 电压监控器是一种用于监测电力系统中电压水平的设备。它通常用于检测电压的变化、波动或异常情况&#xff0c;以确保电力系统的稳定运行。电压监控器可以监测不同电压水平&#xff0c;例如交流电系统中的电压、直流电系统中的电压等并将其显示在…

【中危】 Apache Traffic Server Range 标头验证不当

漏洞描述 Apache Traffic Server&#xff08;ATS&#xff09;是一个开源的反向代理和缓存服务器。 受影响版本中&#xff0c;由于 HttpTransact 类未对无效 Range 标头进行过滤&#xff0c;并且 URL 类未对传入 URL 参数的重复斜杠进行过滤&#xff0c;攻击者可利用此漏洞对 …

docker-compose部署milvus

部署milvus 上一篇介绍了使用kubernetes来部署milvus&#xff0c;这篇介绍下使用docker-compose来部署milvus。 下载docker-compose docker-compose的Github地址https://github.com/docker/compose/releases下载最新版的 docker-compose-linux-x86_64 在服务器上使用 wget …

问道管理:燃气板块拉升走高,胜通能源涨停,欧洲天然气价飙升

燃气板块10日盘中发力走高&#xff0c;到发稿&#xff0c;美能动力、胜通动力、水发燃气涨停&#xff0c;首华燃气涨约8%&#xff0c;山东墨龙、贵州燃气涨逾7%&#xff0c;贝肯动力涨逾5%。 消息面上&#xff0c;因液化天然气供给危险添加&#xff0c;美国天然气期货日内大涨7…

【数据结构OJ题】合并两个有序数组

原题链接&#xff1a;https://leetcode.cn/problems/merge-sorted-array/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 看到这道题&#xff0c;我们注意到nums1[ ]和nums2[ ]两个数组都是非递减的。所以我们很容易想到额外开一个数组tmp[ ]&#x…

大运空瓶行动,绘就生态文明画卷

随着成都第31届世界大学生夏季运动会赛事的成功举办&#xff0c;为了倡导节约水资源、绿色大运&#xff0c;在此之前成都电视2台《城视民生》栏目面向全市发起“大运空瓶行动”的倡议&#xff0c;呼吁市民杜绝水资源浪费&#xff0c;喝完瓶中水&#xff0c;并鼓励市民积极参与到…

vscode-启动cljs

打开vscode &#xff0c;打开cljs项目文件 先npm installvscode安装插件Calva: Clojure & ClojureScript启动REPL 选择Start yout project with a REPL and connect(a.k.a. jack) 后选择shadow-cljs&#xff0c;然后选择shadow&#xff0c;如果需要选择build的话&#xf…

【香瓜说职场】漫长的瓶颈期(2019.03.29)

自从17年4月份开始辞职创业&#xff0c;已经2年了。聊聊近况。 一、公司现状 1、关于淘宝店 淘宝店上架了些开发板相关的衍生产品&#xff0c;单品销量很低&#xff0c;但通过种类来获取销售额。尽管如此&#xff0c;依然不足以支付我和客服两人的工资费用。每月亏损几千。 2、…

【插入排序】直接插入排序 与 希尔排序

目录 1. 排序的概念&#xff1a; 2.插入排序基本思想 3.直接插入排序 4.希尔排序 1. 排序的概念&#xff1a; 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xf…

儿童滑梯CE认证标准EN71测试标准

我国是玩具出口大国&#xff0c;目前的主要出口目标市场是欧洲市场&#xff0c;其中出口欧洲市场的玩具平均约占据我国玩具年出口额的40%左右。 EN 71是欧盟国家强制执行的标准&#xff0c;针对为14岁以下的儿童设计的玩具。其意义是通过EN71标准对进入欧洲市场的玩具产品进行…