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.
Example:
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] of size 4.
Note:
1 is a super ugly number for any given primes.
The given numbers in primes are in ascending order.
0 < k ≤ 100, 0 < n ≤ 10^6, 0 < primes[i] < 1000.
The nth super ugly number is guaranteed to fit in a 32-bit signed integer.
之前做过一道题是Ugly Number II,这道题是按照顺序找出第n个质数因子在2,3,5这个集合中的数字。
做法是利用2,3,5这三个数互乘,并按照大小排好次序,并返回第n个数字,顺序如下2,3,4,5,6,8,9,10.....
那么是否存在某一个数的质数因子全都是2,3,5这个集合中的,但是又不能通过这三个数互乘得到呢,加入存在这样这一个数N,那么N=A*B,A和B中A为质数,A是2,3,5中的一个,B不是一个质数,那么B可以分解为E和F,即B=E*F,那么如果E,F中,E为质数,那么N=A*B=(A*F)*E,因为A的质数因子属于{2,3,5},所以E属于{2,3,5},同样,如果F为一个质数也必然属于{2,3,5},如果F为一个合数,那么它的所有因子也都属于{2,3,5},否则的话,就不能满足A的所有质数因子都属于{2,3,5}这个条件。
那么我们就利用2,3,5这三个数字互乘,得到所有的可能,并按照大小顺序排好,最终得到第n项。
明白了Ugly Number II,那么Super Ugly Number也可以直接做了,不过使用不同的数据结构,耗时差异很大,下面的代码使用的是set,利用set的自动排序,但是差点超时。
int nthSuperUglyNumber(int n, vector<int>& primes)
{
if (n == 1)return 1;
vector<int> nums;
nums.push_back(1);
vector<int> list(primes.size(), 0);
set<int> se;
while (nums.size() < n)
{
se.clear();
for (int i = 0; i < primes.size(); i++)se.insert(nums[list[i]] * primes[i]);
if (*(se.begin()) != nums.back())nums.push_back(*(se.begin()));
for (int i = 0; i < list.size(); i++)if (nums.back() == nums[list[i]] * primes[i]){list[i]++; break;}
}
return nums.back();
}
下面的代码使用的基本数据类型,速度比上面的快上很多。
int nthSuperUglyNumber(int n, vector<int>& primes)
{
if (n == 1)return 1;
vector<int> nums;
nums.push_back(1);
vector<int> list(primes.size(), 0);
while (nums.size() < n)
{
int temp = INT_MAX;
for (int i = 0; i < primes.size(); i++)temp = min(temp, nums[list[i]] * primes[i]);
if(nums.back() != temp)nums.push_back(temp);
for (int i = 0; i < list.size(); i++)if (nums.back() == nums[list[i]] * primes[i]) { list[i]++; break; }
}
return nums.back();
}