[LeetCode] 313. Super Ugly Number

A super ugly number is a positive integer whose prime factors are in the array primes.

Given an integer n and an array of integers primes, return the nth super ugly number.

The nth super ugly number is guaranteed to fit in a 32-bit signed integer.

Example 1:

Input: n = 12, primes = [2,7,13,19]
Output: 32
Explanation: [1,2,4,7,8,13,14,16,19,26,28,32] is the sequence of the first 12 super ugly numbers given primes = [2,7,13,19].

Example 2:

Input: n = 1, primes = [2,3,5]
Output: 1
Explanation: 1 has no prime factors, therefore all of its prime factors are in the array primes = [2,3,5].

Constraints:

  • 1 <= n <= 106
  • 1 <= primes.length <= 100
  • 2 <= primes[i] <= 1000
  • primes[i] is guaranteed to be a prime number.
  • All the values of primes are unique and sorted in ascending order.

超级丑数。

超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。

给你一个整数 n 和一个整数数组 primes ,返回第 n 个 超级丑数 。

题目数据保证第 n 个 超级丑数 在 32-bit 带符号整数范围内。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/super-ugly-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

由于题意定义了超级丑数是由给定的 primes 数组生成的,而最小的超级丑数是 1,所以我们需要一个最小堆,首先把 1 放进去。其余的丑数都是由最小堆堆顶的数字 * primes数组里的每一个数字产生而来的。同时我们从最小堆中不断弹出元素,直到我们弹出第 N 个元素位置。这道题会想到这样做不太难,但是朴素的优先队列的做法速度很慢。

时间:令 [公式] 长度为 [公式],需要从优先队列(堆)中弹出 [公式] 个元素,每次弹出最多需要放入 [公式] 个元素,堆中最多有 [公式] 个元素。复杂度为 [公式]

空间:[公式]

Java实现

 1 class Solution {
 2     public int nthSuperUglyNumber(int n, int[] primes) {
 3         HashSet<Long> set = new HashSet<>();
 4         PriorityQueue<Long> heap = new PriorityQueue<>();
 5         set.add(1L);
 6         heap.offer(1L);
 7         int ugly = 0;
 8         for (int i = 0; i < n; i++) {
 9             long cur = heap.poll();
10             ugly = (int) cur;
11             for (int p : primes) {
12                 long next = cur * p;
13                 if (set.add(next)) {
14                     heap.offer(next);
15                 }
16             }
17         }
18         return ugly;
19     }
20 }

 

比较优化的思路是多路归并,还是会用到最小堆。这里我参考了这个帖子。这个思路优化的重点在于他用了多路归并,这样对于 primes 数组里的每一个数字 primes[i],我们都去试图模拟一个由 primes[i] 生成的丑数的序列,然后每个序列都给一个指针,我们每次只把全局最小的那个丑数放入最小堆。但是从实际做法来看,我们不需要真的创建那么多丑数序列,这个部分可以通过往最小堆中放入的元素来记录。

时间:需要构造长度为 [公式] 的答案,每次构造需要往堆中取出和放入元素,堆中有 [公式] 个元素,起始时,需要对 [公式] 进行遍历,复杂度为 [公式]。整体复杂度为 [公式]

空间:存储 [公式] 个答案,堆中有 [公式] 个元素,复杂度为 [公式]

Java实现

 1 class Solution {
 2     public int nthSuperUglyNumber(int n, int[] primes) {
 3         int len = primes.length;
 4         PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[0] - b[0]);
 5         for (int i = 0; i < len; i++) {
 6             queue.offer(new int[] { primes[i], i, 0 });
 7         }
 8 
 9         int[] res = new int[n];
10         res[0] = 1;
11         for (int j = 1; j < n;) {
12             int[] cur = queue.poll();
13             int val = cur[0];
14             int i = cur[1];
15             int idx = cur[2];
16             if (val != res[j - 1]) {
17                 res[j++] = val;
18             }
19             queue.offer(new int[] { res[idx + 1] * primes[i], i, idx + 1 });
20         }
21         return res[n - 1];
22     }
23 }

 

LeetCode 题目总结

posted @ 2021-08-09 23:37  CNoodle  阅读(270)  评论(0编辑  收藏  举报