每日一题之 264. 丑数 II

题目1:
给你一个整数 n ,请你找出并返回第 n 个 丑数 。
丑数 就是只包含质因数 2、3 和/或 5 的正整数。

示例 1:
输入:n = 10
输出:12
解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。
示例 2:

输入:n = 1
输出:1
解释:1 通常被视为丑数。

提示:
1 <= n <= 1690
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:
方法1:
优先队列。
起始先将最小丑数 1放入队列,
每次从队列取出最小值 xx,然后将 xx 所对应的丑数 2x2x、3x3x 和 5x5x 进行入队。
对步骤 2 循环多次,第 nn 次出队的值即是答案。
为了防止同一丑数多次进队,我们需要使用数据结构 SetSet 来记录入过队列的丑数。

方法2:
多队列归并
可以发现后续的每一个丑数都是又前面经过质因数计算得到的。
那么我们可以将三个队列进行归并,每次取其中的最小值;
直到取到第n个。

//优先队列
class Solution {
    int[] nums = new int[] {2,3,5};
    public int nthUglyNumber(int n) {
        //int越界, 所以取long
        Set<Long> set = new HashSet<> ();
        //优先队列
        Queue<Long> pq = new PriorityQueue<> ();
        //
        set.add (1L);
        pq.add (1L);

        for (int i = 1; i <= n ;i++) {
            //取优先队列的最小值
            long x = pq.poll ();
            //取到n时直接return
            if (i == n) {
                return (int)x;
            }

            for (int y: nums) {
                long ans = x * y;

                //如果不在该set中,直接添加
                if (!set.contains (ans) ) {
                    pq.add (ans);
                    set.add (ans);
                }
            }
        }
        return -1;
    }
}

//三个队列归并
class Solution {
    public int nthUglyNumber(int n) {
        // ans 用作存储已有丑数(从下标 1 开始存储,第一个丑数为 1)
        int[] ans = new int[n + 1];
        ans[1] = 1;
        // 由于三个有序序列都是由「已有丑数」*「质因数」而来
        // i2、i3 和 i5 分别代表三个有序序列当前使用到哪一位「已有丑数」下标(起始都指向 1)
        for (int i2 = 1, i3 = 1, i5 = 1, idx = 2; idx <= n; idx++) {
            // 由 ans[iX] * X 可得当前有序序列指向哪一位
            int a = ans[i2] * 2, b = ans[i3] * 3, c = ans[i5] * 5;
            // 将三个有序序列中的最小一位存入「已有丑数」序列,并将其下标后移
            int min = Math.min(a, Math.min(b, c));
            // 由于可能不同有序序列之间产生相同丑数,因此只要一样的丑数就跳过(不能使用 else if )
            if (min == a) i2++; 
            if (min == b) i3++;
            if (min == c) i5++;
            ans[idx] = min;
        }
        return ans[n];
    }
}

参考资料:
【宫水三叶】一题双解:优先队列 & 多路归并

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值