题目:
Write a program to find the nth super ugly number.
Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes
of size k
. For example, [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]
of size 4.
Note:
(1) 1
is a super ugly number for any given primes
.
(2) The given numbers in primes
are in ascending order.
(3) 0 < k
≤ 100, 0 < n
≤ 106, 0 < primes[i]
< 1000.
题意:
写一个程序去找到第n个“超级丑数”,超级丑数定义为:
超级丑数是指只包含给定的k个质因子的正数,例如,给定长度为4的质数序列primes = [2, 7, 13, 19],前12个超级丑陋数序列为:[1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32]
注意:
1、1被认为是超级丑数,无论给定怎样的质数列表。
2、给定的质数列表以升序排列。
3、0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000。
转载地址:https://leetcode.com/discuss/81411/java-three-methods-23ms-58ms-with-heap-performance-explained
思路一:
和 leetcode Ugly Number II 思路一样,要使得super ugly number 不漏掉,那么用每个因子去乘第一个,当前因子乘积是最小后,乘以下一个…..以此类推。
代码:java版:34ms
public class Solution { public int nthSuperUglyNumber(int n, int[] primes) { int[] ugly = new int[n]; int[] idx = new int[primes.length]; ugly[0] = 1; for (int i=1; i<n; i++) { //找到下一个ugly number ugly[i] = Integer.MAX_VALUE; for (int j=0; j<primes.length; j++) { ugly[i] = Math.min(ugly[i], primes[j]*ugly[idx[j]]); } //跳过重复值 for (int j=0; j<primes.length; j++) { while (primes[j] * ugly[idx[j]] <= ugly[i]) idx[j]++; } } return ugly[n-1]; } }
思路二:
观察上面算法可以看到,依然还是有一部分冗余的乘法可以避免,并且可以将两次循环综合成一次。主要是利用空间换时间。将每一次循环产生的几个丑数都分别保存到数组中。
代码:java版:23ms
public class Solution { public int nthSuperUglyNumber(int n, int[] primes) { int[] ugly = new int[n]; int[] idx = new int[primes.length]; int[] val = new int[primes.length]; Arrays.fill(val, 1); int next = 1; for (int i=0; i<n; i++) { ugly[i] = next; next = Integer.MAX_VALUE; for (int j=0; j<primes.length; j++) { //跳过重复值以及冗余的乘法操作 if (val[j] == ugly[i]) val[j] = ugly[idx[j]++] * primes[j]; //找到下一个ugly number next = Math.min(next, val[j]); } } return ugly[n - 1]; } }
思路三:
理论上可以通过将每一个候选值放到堆中来改善运行的时间复杂度,但是实际上并没有优于以上两种写法,可能是由于java中使用了较高级别的对象而不是最基础的。
代码:java版:60ms
public class Solution { public int nthSuperUglyNumber(int n, int[] primes) { int[] ugly = new int[n]; PriorityQueue<Num> pq = new PriorityQueue<>(); for (int i = 0; i < primes.length; i++) pq.add(new Num(primes[i], 1, primes[i])); ugly[0] = 1; for (int i = 1; i < n; i++) { ugly[i] = pq.peek().val; while (pq.peek().val == ugly[i]) { Num nxt = pq.poll(); pq.add(new Num(nxt.p * ugly[nxt.idx], nxt.idx + 1, nxt.p)); } } return ugly[n - 1]; } private class Num implements Comparable<Num> { int val; int idx; int p; public Num(int val, int idx, int p) { this.val = val; this.idx = idx; this.p = p; } @Override public int compareTo(Num that) { return this.val - that.val; } } }