313. Super Ugly Number

23 篇文章 1 订阅

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.

这一题主要是理清楚数学上怎么回事,factor是因子,prime factor就是质数因子。给定几个质数,产生一个序列,序列里的数包含的质数因子必须在这几个数当中。
设一个数X, 假设它可以分解为X = a * b, 如果a, b都是质数,则a, b必须都在prime里,如果b是合数,那分解b如果得到质数也必须在prime里,所以b也属于最后要求的数一种,所以以此类推,后面产生的数一定可以通过给定的prime序列和已有的前面的结果相乘得到。
很容易想到的一个问题就是如何不重复不遗漏,下面介绍本题基本方法.
方法一:复杂度O(n*k)
C++源码:

int nthSuperUglyNumber(int n, vector<int>& primes) {
    vector<int> res(n); // 记录输出结果
    int k = primes.size();
    vector<int> pos(k, 0); // 记录每一个prime质数已经乘过的位置
    int i, j, temp;
    res[0] = 1; // 1是固定的起始位置
    for (i = 1; i < n; i++) {
        temp = INT_MAX;
        for (j = 0; j < k; j++) {
            temp = min(temp, res[pos[j]] * primes[j]);
        }
        for (j = 0; j < k; j++) {
            if (temp == res[pos[j]] * primes[j])
                pos[j]++;
        }// 这个for循环是为了找出上一轮中所有的最小值,所有都加一,消除重复,否则下一轮最小还是它
        res[i] = temp;
    }

    return res[n-1];

}

方法二: 复杂度O(nlogk)
C++:

struct Node {
    int index, val, prime;
    Node(int in, int va, int pr) {
        index = in;
        val = va;
        prime = pr;
    }
    bool operator < (const Node& b) const{
        return val > b.val;
    } // 新定义这个大于变小于只是为了把priority queue里默认的maxheap改成minheap,也可在定义处改
};

class Solution {
public:
    int nthSuperUglyNumber(int n, vector<int>& primes) {
        vector<int> res(n);
        priority_queue<Node> q;
        res[0] = 1;
        int k = primes.size();
        for (int i = 0; i < k; i++) {
            q.push(Node(0, primes[i], primes[i]));
        } // 把所有的prime归置到这个queue里,0代表目前大家的index,val等于prime基本值因为输出第一     
          // 个是1, prime[i]乘以1还是自己
        for (int i = 1; i < n; i++) {
            Node cur = q.top();
            res[i] = cur.val; //直接将最小的赋值给输出现有位置
            do {
                cur = q.top();//再取一次是因为如果产生循环,第二次的cur需要重新取新的top
                q.pop();
                cur.val = cur.prime*res[++cur.index];
                q.push(cur);
            } while (!q.empty() && q.top().val == res[i]);
        }// 先执行再判断,避免有多个相同最小值

        return res[n - 1];
   }
};

这题用不用数据结构区别不大,算法复杂度相似,第二种分析起来因为每次都是对优先队列操作,也就是几次logk的操作,方法一种是将k长序列线性过了两边,一边找最小,一边改所有最小。看起来是二要快一些,实际上leetcode结果一更快。。。whatever,这个无所谓。两种都把问题较好的解决了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值