class Solution:
def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int:
ugly = [1]
idx = [0] * len(primes)
values = list(primes)
for i in range(1, n):
next_ugly = min(values)
ugly.append(next_ugly)
for j in range(len(primes)):
if values[j] == next_ugly:
idx[j] += 1
values[j] = ugly[idx[j]] * primes[j]
return ugly[-1]
class Solution {
public:
int nthSuperUglyNumber(int n, vector<int>& primes) {
vector<int> ugly(n, 1);
vector<int> idx(primes.size(), 0);
vector<long> values(primes.begin(), primes.end());
for (int i = 1; i < n; ++i) {
long next_ugly = *min_element(values.begin(), values.end());
ugly[i] = (int)next_ugly;
for (int j = 0; j < primes.size(); ++j) {
if (values[j] == next_ugly) {
idx[j]++;
values[j] = (long)ugly[idx[j]] * primes[j];
}
}
}
return ugly[n-1];
}
};
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
int[] ugly = new int[n];
ugly[0] = 1;
int[] idx = new int[primes.length];
int[] values = primes.clone();
for (int i = 1; i < n; i++) {
int nextUgly = Integer.MAX_VALUE;
for (int v : values) nextUgly = Math.min(nextUgly, v);
ugly[i] = nextUgly;
for (int j = 0; j < primes.length; j++) {
if (values[j] == nextUgly) {
idx[j]++;
values[j] = ugly[idx[j]] * primes[j];
}
}
}
return ugly[n - 1];
}
}
var nthSuperUglyNumber = function(n, primes) {
let ugly = [1];
let idx = new Array(primes.length).fill(0);
let values = primes.slice();
for (let i = 1; i < n; i++) {
let nextUgly = Math.min(...values);
ugly.push(nextUgly);
for (let j = 0; j < primes.length; j++) {
if (values[j] === nextUgly) {
idx[j]++;
values[j] = ugly[idx[j]] * primes[j];
}
}
}
return ugly[ugly.length - 1];
};
The "Super Ugly Number" problem asks you to find the n
th super ugly number, given a list of prime numbers primes
.
A super ugly number is a positive integer whose prime factors are only from the list primes
. By convention, 1 is considered a super ugly number.
Your task is to generate the sequence of super ugly numbers in ascending order and return the n
th element in this sequence.
n
(1 ≤ n ≤ 106), and a list of prime numbers primes
(length ≤ 100, each prime ≤ 1000).n
th super ugly number.primes
. The sequence must be in ascending order and contain no duplicates.
At first glance, generating all possible products of the given primes and sorting them to find the n
th smallest seems straightforward.
However, this approach quickly becomes infeasible as n
grows large, due to the exponential number of combinations.
We need a method to build the sequence incrementally, always keeping it sorted and avoiding duplicates.
The classic "Ugly Number" problem (where the prime set is [2,3,5]) is typically solved using dynamic programming with pointers for each prime. We can generalize this technique: for each prime, keep track of which previous super ugly number to multiply by that prime next. By always picking the minimum candidate, we build the sequence in order, efficiently and without duplicates.
We use a dynamic programming approach with multiple pointers, one for each prime in the list. The idea is to incrementally build an array of the first n
super ugly numbers.
ugly
to store the super ugly numbers, initialized with 1 as the first element.idx
(all start at 0), indicating which element in ugly
to multiply by that prime next.values
, where values[i]
is the next candidate super ugly number for primes[i]
(initialized as primes[i]
).n-1
in ugly
:values
— this is the next super ugly number.ugly
.ugly
up to n
elements, return ugly[n-1]
.This approach leverages the fact that every super ugly number can be produced by multiplying a previous super ugly number by one of the primes, and by always choosing the smallest next candidate, we maintain order and avoid unnecessary computation.
Let's walk through the process for n = 12
and primes = [2, 7, 13, 19]
:
ugly = [1]
, idx = [0, 0, 0, 0]
, values = [2, 7, 13, 19]
.
ugly
. Increment idx[0] to 1. Now, values[0] = ugly[1] * 2 = 4
.
values[0] = ugly[2] * 2 = 8
.
values[1] = ugly[1] * 7 = 14
.
values[0] = ugly[3] * 2 = 14
.
values[2] = ugly[1] * 13 = 26
.
values[0] = ugly[4]*2=16
, values[1]=ugly[2]*7=28
.
Each step, we only consider the next possible multiples, never missing or repeating a value.
Brute-force approach:
n
th number, which is exponential and infeasible for large n
.n
super ugly numbers is generated in a loop, and for each, we scan through k
primes to update pointers and candidates. Thus, total time complexity is O(nk)
, where k
is the number of primes.O(n + k)
: O(n)
for the ugly number list, O(k)
for indices and candidate values.
Since both n
and k
are constrained (n ≤ 106, k ≤ 100), this is efficient enough for practical use.
The Super Ugly Number problem is an elegant extension of the classic Ugly Number sequence, generalized to any set of primes.
By using dynamic programming with pointers for each prime, we efficiently generate the sequence in order, ensuring no duplicates, and can quickly find the n
th super ugly number.
The key insight is to always multiply the next candidate for each prime and take the minimum, which keeps the process both correct and efficient.