leetcode每日一题系列-超级丑数

460 阅读2分钟

这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战

leetcode-313-超级丑数

[博客链接]

菜🐔的学习之路

掘金首页

[题目描述]

超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。

给你一个整数 n 和一个整数数组 primes ,返回第 n 个 超级丑数 。

题目数据保证第 n 个 超级丑数 在 32-bit 带符号整数范围内。

示例 1:

输入: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] 。

示例 2:

输入:n = 1, primes = [2,3,5]
输出:1
解释:1 不含质因数,因此它的所有质因数都在质数数组 primes = [2,3,5] 中。

提示:

  • 1 <= n <= 106
  • 1 <= primes.length <= 100
  • 2 <= primes[i] <= 1000
  • 题目数据 保证 primes[i] 是一个质数
  • primes 中的所有值都 互不相同 ,且按 递增顺序 排列

Related Topics

  • 数组
  • 哈希表
  • 数学
  • 动态规划
  • 堆(优先队列)
  • 👍 188 👎 0

[题目链接]

leetcode题目链接

[github地址]

代码链接

[思路介绍]

思路一:优先队列+hash

  • 扫描递增数组
  • TreeSet + 优先队列还是很好考虑到的
  • 但是如何维护递增属实是我没想到的
  • 后来一想,原来如此简单
  • 通过n计数
  • set去重
  • 优先队列维护小根堆
public int nthSuperUglyNumber(int n, int[] primes) {
            Set<Long> set = new HashSet<>();
            PriorityQueue<Long> priorityQueue = new PriorityQueue<>();
            priorityQueue.add(1L);
            set.add(1L);
            while (n-- > 0) {
                long val = priorityQueue.poll();
                if (n == 0){
                    return (int)val;
                }
                for (int num: primes
                     ) {
                    if (!set.contains(num*val)){
                        set.add(num*val);
                        priorityQueue.add(num*val);
                    }
                }
​
            }
            return -1;
        }
  • 时间复杂度O(nm * lg(nm))

  • 空间复杂度O(n*m)


    思路二:多路归并

    • 不难发现的是下一个丑数都是由之前的丑数*输入数组的质因子实现
    • 主要是找到最近遍历的最小元素*最近遍历的最小输入因子
    • 三叶大佬三元组小根堆就很秀
     public int nthSuperUglyNumber(int n, int[] primes) {
                int m = primes.length;
                PriorityQueue<int[]> q = new PriorityQueue<>((a, b) -> a[0] - b[0]);
                for (int i = 0; i < m; i++) {
                    q.add(new int[]{primes[i], i, 0});
                }
                int[] ans = new int[n];
                //初始化第一个一定是1
                ans[0] = 1;
                for (int j = 1; j < n;) {
                    int[] temp = q.poll();
                    int val = temp[0], i = temp[1], idx = temp[2];
                    //维护单调递增
                    if (val != ans[j - 1]) ans[j++] = val;
                    //这个步骤可以重复写ans数组保证丑数相邻关系
                    q.add(new int[]{ans[idx + 1] * primes[i], i, idx + 1});
                }
                return ans[n - 1];
            }
    
    • 时间复杂度O(max{n*lgm,m})
    • 空间复杂度O(n+m)