数据结构与算法之堆: LeetCode 313. 超级丑数(Ts, Py, Go版)

【数据结构与算法】之深入解析“超级丑数”的求解思路与算法示例 一、题目要求 超级丑数是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。 给你一个整数 n 和一个整数数组 primes ,返回第 n 个超级丑数 。 题目数据保证第 n 个超级丑数在 32-bit 带符号整数范围内。 示例 1: 输入:n = 12, primes = [2,7,13,19] 输出:32 解释:给定长度为 4 的质数数组 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。 示 阅读详情

超级丑数

  • https://leetcode.cn/problems/super-ugly-number/

描述

  • 超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。
  • 给你一个整数 n 和一个整数数组 primes ,返回第 n 个 超级丑数 。
  • 题目数据保证第 n 个 超级丑数 在 32-bit 带符号整数范围内。

示例 1

输入:n = 12, primes = [2,7,13,19]
输出:32 
解释:给定长度为 4 的质数数组 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。

示例 2

输入:n = 1, primes = [2,3,5]
输出:1
解释:1 不含质因数,因此它的所有质因数都在质数数组 primes = [2,3,5] 中。

提示

  • 1 <= n <= 10510^5105
  • 1 <= primes.length <= 100
  • 2 <= primes[i] <= 1000
  • 题目数据 保证 primes[i] 是一个质数
  • primes 中的所有值都 互不相同 ,且按 递增顺序 排列

Typescript 版算法实现

  • 首先要了解下质数
    • 又称素数,有无限个
    • 质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数
  • 再看下质因数
    • 是一个数的约数,并且是质数
  • 再次要了解丑数
    • 只包含因子2,3,5的正整数被称为丑数,比如4,10,12都是丑数,而7,23,111则不是丑数,另外1也是丑数
  • 超级丑数
    • 和丑数不是一回事
    • 是指所有质因数都是长度为k的质数列表primes中的正整数

1 )将问题分而治之

class Ugly {
  n: number = 0;
  primes: number[] = [];
  constructor (n: number, primes: number[]) {
    this.n = n;
    this.primes = primes;
  }
  // 获取第n个超级丑数,本质是一个查询操作
  getNthUg() {
    const res = [1]; // 超级丑数列表
    let i = 2; // 从2开始找
    const { primes, n } = this;
    while (res.length < n) {
      const arr = Ugly.getPrimes(i); // 获取当前i的所有质因数列表
      const l = arr.length; // 质因数列表长度的
      let j = 0; // 指针往上数
      // 遍历当前i的所有质因数找到和primes列表中匹配的质因数, 有一个不匹配都算失败
      for (; j < l; j++) {
        // 匹配不到则退出
        if (!primes.find(item => item === arr[j])) break;
      }
      // 这时候上面的for循环遍历完成, 而且当前i的所有质因数都匹配成功, 就可以进行下一步的操作
      if (j === l) {
        (l === 0) && primes.find((item) => item === i) && res.push(i); // 当前没有质因数(上面for不会执行),但是当前的i在给定列表中,存储i(满足超级丑数)
        (l !== 0) && res.push(i); // 当前i存在质因数列表时,存储 i(满足超级丑数)
      }
      i++; // i 递增
    }
    return res[n - 1]; // 获取第n个
  }
  // 计算指定正整数n的质因数
  static getPrimes (n) {
    const prime = (n) => {
      const arr = []; // 存储所有的质因数
      for (let i = 2; i <= n / 2; i++) {
        if (n % i === 0 && !prime(i).length) arr.push(i); // 这里有一个递归找质因数
      }
      return arr;
    }
    return prime(n);
  }
}

function nthSuperUglyNumber(n: number, primes: number[]): number {
  const ugly = new Ugly(n, primes);
  return ugly.getNthUg();
};
  • 思路:
    • 给定任意整数,算出其质因数
    • 质因数是否在指定质因数范围内
    • 是否达到指定个数 n
  • 干扰点:丑数和超级丑数不是一回事
  • 正整数的质因数的算法
    • 如果这个正整数是n, 它的因数(约数)的范围一定在 [2, n/2]
    • 当然这个 n/2 可能不是整数,但是范围就在这儿
    • 先判断是否是因数: n能被i整除
    • 质因数:不仅要满足是因数,而且都是质数(除了1和它本身没有其他因数)
    • 质数如何解决呢,这里就用到了递归,如果整数后找不到其他因数,则本身就是质数
    • 这里 !prime(i).length 是判断质数的关键
  • 还要注意 getNthUg 方法中的查询操作,这是一个循规蹈矩的做法,但是性能很低
    • 性能瓶颈在,查找两个数组的方法
    • 目前在 第 77 个 case 的时候, 提示:超出时间限制
    • 我们需要提升查找效率

2 )使用堆结构来提升查找性能,优化版

class Ugly {
  n: number = 0;
  primes: MaxHeap;
  constructor (n: number, primes: number[]) {
    this.n = n;
    this.primes = new MaxHeap(primes);
  }
  // 获取第n个超级丑数,本质是一个查询操作
  getNthUg() {
    const res = [1];
    let i = 2; // 从2开始找
    const { primes, n } = this;
    while (res.length < n) {
      const arr = Ugly.getPrimes(i); // 获取当前i的所有质因数列表
      const l = arr.length; // 质因数列表长度的
      let j = 0; // 指针往上数
      // 遍历当前i的所有质因数找到和primes列表中匹配的质因数, 有一个不匹配都算失败
      for (; j < l; j++) {
        // 匹配不到则退出
        if (!primes.find(arr[j])) break;
      }
      // 这时候上面的for循环遍历完成, 而且当前i的所有质因数都匹配成功, 就可以进行下一步的操作
      if (j === l) {
        (l === 0) && primes.find(i) && res.push(i); // 当前没有质因数(上面for不会执行),但是当前的i在给定列表中,存储i(满足超级丑数)
        (l !== 0) && res.push(i); // 当前i存在质因数列表时,存储 i(满足超级丑数)
      }
      i++; // i 递增
    }
    return res[n - 1]; // 获取第n个
  }
  // 计算指定正整数n的质因数
  static getPrimes (n) {
    const prime = (n) => {
      const arr = []; // 存储所有的质因数
      for (let i = 2; i <= n / 2; i++) {
        if (n % i === 0 && !prime(i).length) arr.push(i); // 这里有一个递归找质因数
      }
      return arr;
    }
    return prime(n);
  }
}

class MaxHeap {
  heap: number[] = [];
  max: number = 0;
  constructor (arr) {
    this.heap = arr;
    this.max = arr.length;
    this.sort();
  }
  sort () {
    const iArr = this.heap;
    const n = iArr.length;
    if (n <= 1) return iArr;
    for (let i = Math.floor(n / 2); i >= 0; i--) {
      MaxHeap.maxHeapify(iArr, i, n);
    }
    return iArr;
  }
  // 交换两个元素
  static swap (arr, i, j) {
    if (i === j) return;
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  // 构建最大堆的过程
  static maxHeapify (Arr, i, size) {
    // 左节点(索引)
    const l = i * 2 + 1;
    // 右节点
    const r = i * 2 + 2;
    let largest = i;
    // 父节点i和左节点l做比较取最大
    if (l <= size && Arr[l] > Arr[largest]) largest = l;
    // 右节点和最大值比较
    if (r <= size && Arr[r] > Arr[largest]) largest = r;
    if (largest !== i) {
      MaxHeap.swap(Arr, i, largest)
      MaxHeap.maxHeapify(Arr, largest, size)
    }
  }
  find (val, i = 0) {
    const arr = this.heap;
    if (val > arr[i] || i > this.max) return false;
    if (val === arr[i]) return val;
    return this.find(val, i * 2 + 1) || this.find(val, i * 2 + 2);
  }
}

function nthSuperUglyNumber(n: number, primes: number[]): number {
  const ugly = new Ugly(n, primes);
  return ugly.getNthUg();
};
  • 使用堆结构,取代普通数组结构,让查找效率提升 O(n) => O(logn)
  • 但是这里仍有大量递归运算,消耗太多性能
  • 同样,在第77个case时出现了提示:超出时间限制

3 )使用动态规划

function nthSuperUglyNumber (n: number, primes: number[]) {
    const dp = new Array(n + 1).fill(0);
    const m = primes.length;
    const pointers = new Array(m).fill(0);
    const nums = new Array(m).fill(1);
    for (let i = 1; i <= n; i++) {
        let minNum = Number.MAX_SAFE_INTEGER;
        for (let j = 0; j < m; j++) {
            minNum = Math.min(minNum, nums[j]);
        }
        dp[i] = minNum;
        for (let j = 0; j < m; j++) {
            if (nums[j] == minNum) {
                pointers[j]++;
                nums[j] = dp[pointers[j]] * primes[j];
            }
        }
    }
    return dp[n];
};
  • 这是官方做法, 动态规划解决了递归的问题,由递归变成了递推
  • 时间复杂度 O(nm) ≈ O(n2n^2n2)

Python3 版算法实现


1 ) 方案1: 动态规划

class Solution:
    def nthSuperUglyNumber(self, n: int, primes: list) -> int:
        dp = [0] * (n + 1)
        m = len(primes)
        pointers = [0] * m
        nums = [1] * m
        
        for i in range(1, n + 1):
            min_num = float('inf')
            for j in range(m):
                min_num = min(min_num, nums[j])
            dp[i] = min_num
            for j in range(m):
                if nums[j] == min_num:
                    pointers[j] += 1
                    nums[j] = dp[pointers[j]] * primes[j]
        
        return dp[n]

Golang 版算法实现


1 ) 方案1:动态规划

func nthSuperUglyNumber(n int, primes []int) int {
	dp := make([]int, n+1)
	m := len(primes)
	pointers := make([]int, m)
	nums := make([]int, m)
	for i := 0; i < m; i++ {
		nums[i] = 1
	}

	for i := 1; i <= n; i++ {
		minNum := math.MaxInt64
		for j := 0; j < m; j++ {
			if nums[j] < minNum {
				minNum = nums[j]
			}
		}
		dp[i] = minNum
		for j := 0; j < m; j++ {
			if nums[j] == minNum {
				pointers[j]++
				nums[j] = dp[pointers[j]] * primes[j]
			}
		}
	}

	return dp[n]
}
C++版 - 剑指offer 面试题34:寻找丑数(Leetcode 263.Ugly number)解题报告 剑指offer 面试题34:寻找丑数 题目:把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。请按从小到大的顺序的第N个丑数。(据说google曾经采用过这道题。) 提交网址: http://www.nowcoder.com/practice/6aa9e04fc3794f68acf87 阅读详情

相关推荐

OBS技术深度剖析:从开源直播工具到专业制作引擎的进化之路

本文深入剖析了开源直播软件OBS的技术架构与发展历程。从2012年诞生至今,OBS已成长为直播领域的事实标准,其成功源于模块化设计和开源协作模式。文章详细解析了OBS的核心技术:1) 分层架构与插件系统,2) GPU加速的渲染管线,3) 智能音频处理,4) 多平台编码优化。同时探讨了虚拟摄像头、浏览器源等高级功能的实现原理,并提供了性能优化方案和硬件配置建议。随着AI、WebRTC等新技术发展,OBS将持续引领实时内容创作工具的创新,为开发者和创作者提供更强大的技术支持。

程序猿老樊的博客 333

Leetcode 264:丑数 II(超详细的解法!!!)

编写一个程序,找出第 n 个丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例: 输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 说明: 1 是丑数。 n 不超过1690。 解题思路 这个问题是之前问题Leetcode 263:丑数(超详细的解法!!!)的提高。这个问题首先可以想到通过暴力法解决,n不...

coordinate的博客 2443

【芯片驱动】2. CMT2300A配合硬件测试(灵敏度和发射功率)的软件实现

前言 在开发一款无线射频产品的时候,软件是一部分,硬件也是一部分。而决定无线收发性能的,首先是硬件的匹配电路,然后才到软件部分的优化。 一款无线射频产品,首先需要先决定是在那个频率范围内(当然是国家允许的范围内),然后硬件则需要在基于这个频点范围进行硬件的参数匹配,具体又分为发送功率匹配、天线匹配、和接收灵敏度的匹配。 现在我们使用2300a这款无线芯片来说,除非自己的团队是射频专家,则可以自己进行无线外围电路的设计外,另外一种更加快捷的方式,就是寻找原厂技术支持,他们会给...

sishuihuahua的博客 7056

LeetCode —— 丑数

觉得丑数这个案例不错,主要涉及循环迭代、优先队列+哈希表、动态规划三指针

欢迎来到我的世界 491

机器学习入门基础 | 基于python的高光谱图像特征挖掘:PCA + 形态学属性处理可视化实战

本文介绍了一种基于PCA和形态学操作的高光谱图像特征提取方法。通过主成分分析降低数据维度,再运用面积开闭操作增强空间结构特征,有效去除噪声并填补孔洞。实验采用WHU-HI-HanChuan数据集,提供完整的Python实现代码,包括数据加载、PCA降维、形态学处理及结果可视化等步骤。该方法能够显著改善图像质量,为后续分类和变化检测任务提供更好的特征输入。实验结果表明,不同阈值的形态学处理能呈现不同程度的空间结构增强效果,对区域生长、分割和聚类等应用具有重要价值。

lestatlu的博客 1048

模仿学习与强化学习结合(IL+RL)有没有代表性论文?未来发展趋势如何?

IL与RL的结合正成为AI研究热点,尤其在机器人控制、复杂博弈等需要边学边练的场景。经典方法如Dagger(2010)和GAIL(2016)开创了先用模仿学习预热、再用强化学习微调的模式。近期工作如IN-RIL(2024)提出交替训练策略,显著提升样本效率。开源项目RoboSchool和StableBaselines3为相关研究提供支持。未来趋势包括:1)混合式智能体结合人类经验与自主探索;2)突破小样本学习、自然语言交互等方向;3)提升安全性、样本效率和可解释性。

CyberSoma的博客 2249

LeetCode 丑数

编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例 1: 输入: 6 输出: true 解释: 6 = 2 × 3 示例 2: 输入: 8 输出: true 解释: 8 = 2 × 2 × 2 示例 3: 输入: 14 输出: false 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 说明: 1 是丑数。 输入不会超过 32 位有符号整...

hestyle的博客 619

因子数据预处理-去极值和标准化

多因子数据预处理

cl2010abc的专栏 2423

【leetcode】丑数c++

题目描述: 给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。 丑数 就是只包含质因数 2、3 和/或 5 的正整数。 示例 1: 输入:n = 6 输出:true 解释:6 = 2 × 3 示例 2: 输入:n = 8 输出:true 解释:8 = 2 × 2 × 2 示例 3: 输入:n = 14 输出:false 解释:14 不是丑数,因为它包含了另外一个质因数 7 。 示例 4: 输入:n = 1 输出:true 解释:1 通常被视为

mie haha 549

房产平台系统小程序源码

🏠 一键解锁购房新体验 🔓房产小程序 实现前端 发布二手房 租房 商品 求租 求购等信息;后台发布 新房,二手房租房 商品 写字楼 求租求购等房源信息;功能完善的一块房产小程序。

2401_84413757的博客 796

【OpenCV】手眼标定实战:从原理到calibrateHandEye的完整实现

本文详细解析了机器人视觉中的手眼标定原理与实战,重点介绍了如何使用OpenCV的calibrateHandEye函数实现从数据采集到结果验证的完整流程。文章深入剖析了AX=XB核心方程,区分了眼在手上与眼在手外两种配置,并提供了详细的代码示例与避坑指南,帮助开发者精准建立相机与机械臂末端的坐标转换关系,是机器人精准抓取的关键技术。

weixin_29046611的博客 511

Leetcode 263:丑数(超详细的解法!!!)

编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例 1: 输入: 6 输出: true 解释: 6 = 2 × 3 示例 2: 输入: 8 输出: true 解释: 8 = 2 × 2 × 2 示例 3: 输入: 14 输出: false 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 说明: 1 是丑数。 输入不会超过 32 位有符号...

coordinate的博客 964

MATLAB与图像处理(一):图像中结构张量的求法(Structure Tensor)

1.结构张量的作用:       能够区分图像中的平坦区域,边缘,角点; 2.图像中的结构张量的定义    1)是一个矩阵;    2)与图像的水平,垂直梯度有关,定义如下: 在MATLAB中,可以用如下语句求解:[Ix,Iy]=gradient(Image); 3)求出结构张量矩阵的行列式,和迹(矩阵对角线之和)   行列式:K=det(E);   迹:  

wenyusuran的专栏 5242

Leetcode之丑数系列

263. 编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数2, 3, 5的正整数。 示例 1: 输入: 6 输出: true 解释: 6 = 2 ×3 示例 2: 输入: 8 输出: true 解释: 8 = 2 × 2 ×2 示例3: 输入: 14 输出: false 解释: 14 不是丑数,因为它包含了另外一个质因数7 说明: 1是丑数。 输...

Rain 1831

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

LeetCode-丑数

每日一题,今天刷到一道感觉比较有意思的题,刚开始按自己的思路解答时发现超时了,看到官方的题解后恍然大悟!!!

深夜无眠的博客 515

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

LeetCode题练习与总结:丑数--263

本文详细解析了判断一个数是否为丑数的解题思路和具体实现,涵盖了时间复杂度、空间复杂度分析及Java编程知识点,为解决此类问题提供了清晰的指导。

一直学习永不止步 786

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

leetcode264丑数

lee264 丑数 题目描述:丑数是因子只包含2,3,5的数字,1也算是第一个丑数,求第n大的丑数是什么。 输入:int n 输出:第n大的丑数 思路: 首先1是丑数,将1放入结果数组中。设定一个index2,index3,index5初始化都为0,代表各自的factor已经遍历了结果数组的位置,因为只要结果数组中前一个是丑数,那么它乘上2,3,5肯定也是丑数。然

zsjwish的博客 640

LeetCode-【动态规划】-丑数 II

编写一个程序,找出第 n 个丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例: 输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 说明:   1 是丑数。 n 不超过1690。 题解:参照:https://blog.csdn.net/lhanchao/article/details/52079...

代码屋-CODE HOUSE 1772

[leetcode]Python实现-263.丑数

263.丑数 描述 编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例 输入: 6 输出: true 解释: 6 = 2 × 3 输入: 8 输出: true 解释: 8 = 2 × 2 × 2 输入: 14 输出: false 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 说明: 1...

神不烦 1900

42.丑数-LeetCode-Java

编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例 1: 输入: 6 输出: true 解释: 6 = 2 × 3 示例 2: 输入: 8 输出: true 解释: 8 = 2 × 2 × 2 示例 3: 输入: 14 输出: false 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 说明: 1 是丑数。 输入不会超过 32 位有符号整数的范围: [−231, 231 − 1]。 /** * 方法一:循环整除后看结果是否是 2, 3, 5

思变的博客 200

【LeetCode】丑数系列

一.判断一个数是否为丑数 丑数就是只包含质因数 2, 3, 5 的正整数。 示例1: 输入: 6 输出: true 解释: 6 = 2 × 3 示例2: 输入: 14 输出: false 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 说明: 1 是丑数。 输入不会超过 32 位有符号整数的范围: [−231, 231 − 1]。 Java代码如下: class Soluti...

Rain的博客 284

[leetcode]丑数[javascript]

https://leetcode-cn.com/problems/ugly-number/ 描述 编写一个程序判断给定的数是否为丑数。丑数就是只包含质因数 2, 3, 5 的正整数。示例 1: 输入: 6 输出: true 解释: 6 = 2 × 3 示例 2: 输入: 8 输出: true 解释: 8 = 2 × 2 × 2 示例 3: 输入: 14 输出: false 解释: 14 不是...

迷途之家 299

删除字符串中出现次数最少的字符

题目描述 实现删除字符串中出现次数最少的字符,若多个字符出现次数一样,则都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。 输入描述: 字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。 输出描述: 删除字符串中出现次数最少的字符后的字符串。 输入例子: abcdd 输出例子: dd #include #in

hnxijie的博客 758

LeetCode 263. 丑数

题目描述: 丑数        编写程序判断给定的数是否为丑数。        丑数就是只包含质因子 2, 3, 5 的正整数。例如, 6, 8 是丑数,而 14 不是,因为它包含了另外一个质因子 7。注意:1 也可以被当做丑数。输入不会超过32位整数的范围。代码:class Solution { public: bool isUgly(int num) { if(num ...

江江的博客 741

丑数 -(LeetCode)

题目描述: 编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数2, 3, 5的正整数。 示例 1: 输入: 6 输出: true 解释: 6 = 2 ×3 示例 2: 输入: 8 输出: true 解释: 8 = 2 × 2 ×2 示例3: 输入: 14 输出: false 解释: 14不是丑数,因为它包含了另外一个质因数7。 说明: 1是丑数。...

weixin_43573824的博客 1万+
上一篇: 数据结构与算法之堆: LeetCode 451. 根据字符出现频率排序 (Ts, Py, Go版)
下一篇: 数据结构与算法之图: 图及其深度和广度优先遍历实现 (Ts, Py, Go版)
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值