Leetcode 313. 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.

原题链接:Super Ugly Number

  题目翻译成中文是『超级丑数』,啥叫丑数?丑数就是素因子只有2,3,5的数,7 14 21不是丑数,因为他们都有7这个素数。 这里的超级丑数只是对丑数的一个扩展,超级丑数的素因子不再仅限于2 3 5,而是由题目给定一个素数数组。与朴素丑数算法相比,只是将素因子变了而已,解法还是和朴素丑数一致的。
  之前我说过,凡是任何编程问题都有暴力的解法,此题也一样,大不了对每个数求其所有素因子,然后再判断改素因子是否在给定的数组中,n个数求素因子的算法时间复杂度就是O(n^2)了,何况第n个超级丑数会远大于n,所以凡事不要老想着暴力解决,最好动动脑子。
  我们先来看看丑数数组存在的一个性质,假设我们已经有了一个丑数数组uglys[n],该数组从小到大保存了所有的丑数。你们绝对存在一个x,使得uglys[x]乘以2或3或5等于uglys[i],且x< i。 通俗易懂的解释就是,第i个丑数就是前面i-1个丑数中的某个丑数乘以2 3或5得到的。这条性质成立就是因为丑数的定义是他除了2 3 5没有其他素因子,而非素因子肯定都可以转化为几个素数相乘。 推而广之,这条性质在超级丑数中也成立,理解了这条性质代码也就很好写了。 我们可以通过已知的丑数乘以2 3或5来获得下一个未知的丑数,但未了保证有序,我们每次只取最小的一个。代码如下。

public class Solution {
    public int nthSuperUglyNumber(int n, int[] primes) {
        int k = primes.length;
        int[] uglys = new int[n];
        int[] p = new int[k];
        uglys[0] = 1;
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < k; j++) {
                while (primes[j] * uglys[p[j]] <= uglys[i-i]) {
                    p[j]++;
                }
            }
            uglys[i] = Integer.MAX_VALUE;
            for (int j = 0; j < k; j++) {
                if (primes[j] * uglys[p[j]] > uglys[i - 1]) {
                    uglys[i] = Math.min(primes[j] * uglys[p[j]], uglys[i]);
                }
            }
        }
        return uglys[n-1];
    }
    public static void main(String[] args) {
        Solution s = new Solution();
        int[] primes = {2, 7, 13, 19, 23, 19, 31, 37, 41, 47, 51, 53, 57, 59, 61, 67, 69, 71, 73};
        System.out.println(s.nthSuperUglyNumber(1000000, primes));
    }
}

  可能大家对p数组在这里的意义会有点不理解,p只是一个优化而已。uglys[i]是i前面某个数乘以某个素数,primes素组是免不了要遍历的,但uglys可以不用遍历啊,因为我们再求uglys[i-1]的时候已经验证了某个丑数即便是乘以任意一个给定的素数也不会大于uglys[i-1]的,这里我们需要维护一个性质,任意一个j使得p[j]*primes[j] > uglys[i-1]。
  多数一句,看下数据量,n最大是1000000,k最大是100,所以整个代码最内层循环最大应该是100m,这样算法能在几十毫秒解掉此题,看来leetcode的数据比较水。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xindoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值