Super Ugly Number

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];
    }
};


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值