[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 }