[路飞]_leetcode-313-超级丑数

简介: leetcode-313-超级丑数

网络异常,图片无法展示
|


[题目地址][B站地址]


超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 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 中的所有值都 互不相同 ,且按 递增顺序 排列


解题思路


本题与上一题 leetcode-264-丑数 II 类似, 区别在于上题中质因数是确定的 235,而本题中质因数是通过数组参数传递进来的,但是解题思路是相同的。接下来我们以质因数 235 为例,讲解求得第 n 个丑数的过程。


要求得第 n 个丑数,首先要明确什么是丑数?


丑数的定义:只包含质因数 23 和/或 5 的正整数。


基于以上条件,我们将已经得到的丑数分别和质因数 235 相乘,就得到了后续的丑数


因为 1 是第一个丑数,所以基于以上逻辑可以得到这样的结果。


1 2 3 5 4 6 10 6 9 15 10 15 25 8 12 20 ...
2 3 5
复制代码


但是上面的结果序列有两个问题:


  1. 序列并不是有序的
  2. 存在重复的值


那如何在求得所有丑数的过程中避免以上两个问题呢?


  1. 初始化结果数组并插入第一个元素 1
  2. 定义三个质因数的指针,初始化指向下标 0
  3. 求得每个质因数和其对应指针在结果数组中对应值的乘积
  4. 获取所有乘积中的最小值,该值即下一个丑数
  5. 将最小值对应的质因数的指针向后移动一位
  6. 重复以上过程,直到求得第 n 个丑数


通过以上的过程,保证了求得丑数是严格升序排列的。当多个质因数的乘积有相同的最小值时,将对应质因数指针都向后移动一位,这样就保证了不会有重复的结果。


了解了基于质因数 235求解丑数的过程,只需要把对应质因数换成 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-超级丑数


如有任何问题或建议,欢迎留言讨论!

相关文章