Super Ugly Number

来源:互联网 发布:linux 混合硬盘 编辑:程序博客网 时间:2024/06/05 02:42

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.


解法:

我们先来看来样例中的前12个super ugly number,我们可以得到除了1外,每个super ugly number 都是由一个比它小的super ugly number 和一个primes中prime相乘得到的,这个可以证明一下。对于一个super ugly number A可以分解成A=B*C,其中B在primes[i]中,如果不存在这样的B,如果B=A,则C=1,C为super ugly number,如果B≠A,则C一定是super ugly number,假设不是,则B可以分解成多个质数,使得某个质数不在primes[i]中,因此A就不是super ugly number。

总而言之,一个super ugly number 一定是一个比它小的super ugly number和一个primes[i]中的一个质数相乘。因此我们可以从小到大生成n个super ugly number,那么就要判断第k个super ugly number怎么生成下一个super ugly number,需要哪个super ugly number 和哪个质数相乘呢?我们知道质数的个数最多只有100,而super ugly number的有k个,那么组合数就有100k,但我们要循环n次,这样复杂度就要O(n^2),这样肯定超时。那么我要优化一下,考虑到这种情况,第i个质数参与生成的ugly number,从小到大肯定是第i个质数分别与第1,2,3,4.....j个ugly number相乘的数,因此可以对每个质数维护一个值,表示该质数生成下一个ugly number 所需要相乘的ugly number 的标号,当第i个质数生成下一个ugly number该值就加1。由于每次要从k个质数要生成的下一个ugly number 中找出最小值,我们可以用优先队列实现。因此复杂度是O(n)*O(lgk)=O(nlgk)


struct T{    int prime_index,list_index;//质数所在数组的下标,要相乘的ugly number所在数组的下标    int P,L;//质数的值,ugly number 的值    T(int i,int P1,int L1)    {        prime_index=i;        list_index=0;        P=P1;        L=L1;    }    };bool operator <(const T a,const T b){    return a.P*a.L>b.P*b.L;}class Solution {public:    vector<int> lists;       int nthSuperUglyNumber(int n, vector<int>& primes) {        lists.push_back(1);        priority_queue<T> que;  //优先队列,待生成的ugly number小的在队头        for(int i=0;i<primes.size();++i)        {            que.push(T(i,primes[i],1));                    }        int min=1;                for(int i=1;i<n;++i)        {                        T temp=que.top();            que.pop();                        temp.P=primes[temp.prime_index];            temp.L=lists[temp.list_index];                                  if(min==temp.P*temp.L)i--;//如果ugly number重复,则不计算            else {lists.push_back(temp.P*temp.L);min=temp.P*temp.L;}                        temp.list_index++;  //计算完ugly number后,下一个要相乘的ugly number的下标要加1            temp.L=lists[temp.list_index];            que.push(temp);                    }        return lists[n-1];    }};


0 0
原创粉丝点击