超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 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 <= 1061 <= primes.length <= 1002 <= primes[i] <= 1000- 题目数据 保证
primes[i]是一个质数 primes中的所有值都 互不相同 ,且按 递增顺序 排列
解题思路
本题与上一题 leetcode-264-丑数 II 类似,
区别在于上题中质因数是确定的 2 、 3 、 5,而本题中质因数是通过数组参数传递进来的,但是解题思路是相同的。接下来我们以质因数 2 、 3 、 5 为例,讲解求得第 n 个丑数的过程。
要求得第 n 个丑数,首先要明确什么是丑数?
丑数的定义:只包含质因数 2、3 和/或 5 的正整数。
基于以上条件,我们将已经得到的丑数分别和质因数 2 、 3 、 5 相乘,就得到了后续的丑数
因为 1 是第一个丑数,所以基于以上逻辑可以得到这样的结果。
1 2 3 5 4 6 10 6 9 15 10 15 25 8 12 20 ...
2 3 5
但是上面的结果序列有两个问题:
- 序列并不是有序的
- 存在重复的值
那如何在求得所有丑数的过程中避免以上两个问题呢?
- 初始化结果数组并插入第一个元素
1 - 定义三个质因数的指针,初始化指向下标
0 - 求得每个质因数和其对应指针在结果数组中对应值的乘积
- 获取所有乘积中的最小值,该值即下一个丑数
- 将最小值对应的质因数的指针向后移动一位
- 重复以上过程,直到求得第
n个丑数
通过以上的过程,保证了求得丑数是严格升序排列的。当多个质因数的乘积有相同的最小值时,将对应质因数指针都向后移动一位,这样就保证了不会有重复的结果。
了解了基于质因数 2 、 3 、 5求解丑数的过程,只需要把对应质因数换成 primes 数组即可完成本题。
动画演示
代码实现
var nthSuperUglyNumber = function(n, primes) {
// 创建结果数组
const arr = Array(n).fill(1),
len = primes.length,
// 创建质因数指针
inds = Array(len).fill(0),
// 创建质因数与指针值乘积结果数组
nums = [...primes];
// 遍历求解每一个丑数
for(let i = 1;i<n;i++){
// 获取乘积最小值
const min = Math.min(...nums);
// 更新当前位置丑数
arr[i] = min;
// 更新质因数指针及质因数与指针值乘积结果
for(let j = 0;j<len;j++){
if(min === nums[j]){
inds[j]++;
nums[j] = arr[inds[j]]*primes[j]
}
}
}
// 返回第n个丑数
return arr[n-1]
};
至此我们就完成了 leetcode-313-超级丑数
如有任何问题或建议,欢迎留言讨论!