codecamp

堆 超级丑数

题目

编写一段程序来查找第 n 个超级丑数。

超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。

示例:

输入: n = 12, primes = [2,7,13,19]
输出: 32 
解释: 给定长度为 4 的质数列表 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。

说明:

1 是任何给定 primes 的超级丑数。 给定 primes 中的数字以升序排列。 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000 。 第 n 个超级丑数确保在 32 位有符整数范围内。

解题

简单分析过程:

大家应该都做过丑数的题目。套路就是:为每个质因数建立一个指针,然后再这几个质因数运算的结果中,找出个最小的,然后匹配这个数是由哪个质因数算出来的,把它的指针值+1。 这道题的套路也差不多。只不过,因为我们这次是需要把计算出来的丑数再次和primes里面的质因数结合,算出新的丑数。算出来的丑数放在一个dp数组里。 所以,现在要做的事,怎么能知道每个质因数已经和dp中哪个位置的丑数进行了结合,下一个要结合的位置在哪。就需要建立一个index数组,用来存放每个质因数下一个将要结合的dp的下标,这个下标是从0开始的,每结合一次就+1。extra:有个细节我会在注释里写一下,就是如果出现不同的质因数相乘,乘出来的结果是相同的,是重复的丑数,这个时候该怎么办呢:应该把这几个质因数下一个要结合的dp下标都加1。因为只把其中一个+1的话,下一次计算的丑数一定会是刚才这个重复的丑数,你的结果中就会有很多重复的数,所以,全都加1的话就会把这个重复数给过滤掉了。 好了,现在就可以写代码了。

public class SuperUglyNumber {
    public int nthSuperUglyNumber(int n, int[] primes) {
        int len = primes.length;
        int dp[] = new int[n];
        dp[0] = 1;
        /*梳理一下思路,dp[i]保存的是第i个超级丑数*/
        /*index[i]表示的是primes里面的第i个数下一个将要相乘的数在dp中的位置,
        反过来想,对于每个primes来说,我们都需要和dp中已经算出来的结果相乘算,
        然后取最小的那个作为新的dp元素
        索引index实际上表示是这个素数已经和dp中的哪个位置结合了,下一个位置的坐标是多少 */
        int index[] = new int[len];
        /*可能存在重复的丑数,所以呢,不要在for循环里面加break,把所有的情况都+1*/
        for (int i = 1; i < n; i++) {
            int min = Integer.MAX_VALUE;
            /*遍历对比一下值,找出最小的,*/
            for (int j = 0; j < len; j++) {
                if (min > primes[j] * dp[index[j]]) {
                    min = primes[j] * dp[index[j]];//这个地方就是当前质因数和他要结合的dp
                }
            }
            dp[i] = min;
            /*那个素数要乘以dp的坐标index要加1,向后推一个位
            * 如果存在重复的值,也就是说不同的质因数相乘,得出来相同的结果了,
            * 我们就把这几个位置都+1,这样就可以避免出现重复的值了。
            * 你想想,假如你找到了对应的素数的index,把它加1之后就break掉,那么后面的数也可以算出这个结果,
            * 下次循环的时候,势必会把这个重复的数当成下一个dp,因为这个数肯定要比下一个丑数小
            * 所以我们在for循环中不要加break;*/
            for (int j = 0; j < len; j++) {
                if (min == primes[j] * dp[index[j]]) {
                    index[j]++;
                }
            }


        }
        return dp[n - 1];
    }
}
堆 数据流中的第K大元素
哈希表 分糖果
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

趣味题

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }