[路飞]_超级丑数

149 阅读3分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战

leetcode-313 超级丑数

题目介绍

超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 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 <= 106
  • 1 <= primes.length <= 100
  • 2 <= primes[i] <= 1000
  • 题目数据 保证 primes[i] 是一个质数
  • primes 中的所有值都 互不相同 ,且按 递增顺序 排列

解题思路

本题是 丑数II 的扩展,从 丑数II 的 3 个质因数到不定多个质因数,那么我们解决这道题的方式也和 丑数II 的解决方法类似,只不过从 丑数II 的三指针解法变成多指针解法

我们假设所有符合的丑数都存放在数组 ans 中,那么不在该数组中的数则不是丑数,也就是质因数不止包括 primes 中的数

那么我们用 primes 中的数与 ans 中的任何一个丑数相乘的结果也必然是一个丑数,所以本题的思路就是使用 primes 中的每个值都分别与 ans 中的每一个数相乘,并将结果存放到 ans 数组中

解题步骤

  1. 定义一个数组 ans,用于存放所有的丑数,ans 数组中一开始存放元素 1
  2. 定义一个数组 p, 用于保存 primes 长度个指针,每个指针的指向即为每个 primes 的值需要与之相乘的丑数的位置,每个指针的初始位置都从 0 开始
  3. 比较每个 primes 的值与对应位置的丑数相乘的结果的大小,将最小值插入到 ans 数组中
  4. 然后将相乘结果与最小值相等的指针移动到指向下一个丑数的位置
  5. 重复步骤 3-4 n - 1 次,会得到一个包含 n 个丑数的从小到大排序的数组 ans
  6. 返回 ans 数组的最后一个元素,即为本题的结果

超级丑数.gif

解题代码

var nthSuperUglyNumber = function(n, primes) {
    // 定义 ans 数组用于存放所有的丑数
    const ans = [1]
    // 定义存放指针的数组 p,每个指针的初始值为 0
    const p = new Array(primes.length).fill(0)
    while (--n) {
        let min = Number.MAX_SAFE_INTEGER
        // 获取每个质因数与对应位置的丑数相乘结果的最小值
        for (let i = 0; i < primes.length; i++) {
            min = Math.min(min, primes[i] * ans[p[i]])
        }
        // 将最小值插入到丑数数组中
        ans.push(min)
        // 如果相乘结果与最小值相等的,将相应的指针指向下一个丑数
        for (let i = 0; i < primes.length; i++) {
            if (primes[i] * ans[p[i]] === min) p[i]++
        }
    }
    // 返回第 n 个丑数
    return ans[ans.length - 1]
};