力扣: 49. 丑数

548 阅读2分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

描述

我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。

  • 示例 1:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
  • 提示
1 是丑数。
n 不超过1690。

解析

根据题意,我们可以有下面这种解法:丑数就是质因数只包含 2, 3, 5 的正整数。1是丑数

1.核心就是这句话:保证每个位置的丑数都有生成2、3、5的机会,且不漏过一个值!

2.循环结束后,保证每个位置的丑数都完成了2,3,5这三个操作!只不过重复值不会重复统计

3.确保每个丑数都会完成2,3,5这三个操作,如:b指向的丑数完成了一次3操作,就b++;

4.如果出现这种情况:dp[a] * 2 == dp[b] * 3,那么a和b都会完成自增,表示dp[a]这个丑数完成了2操作,dp[b]这个丑数完成了3操作,所以,下一个需要完成2操作的丑数是dp[a+1],下一个需要完成3操作的丑数是dp[b+1]

示例

class Solution {
    public int nthUglyNumber(int n) {
        int[] dp = new int[n]; //初始化存储丑数的数组
        dp[0] = 1;
        int a=0,b=0,c=0;
        
        for(int i=1;i<n;i++){
        dp[i] = Math.min(Math.min(dp[a]*2,dp[b]*3),dp[c]*5);
        if(dp[i] == dp[a]*2) a++; 
        if(dp[i] == dp[b]*3) b++;
        if(dp[i] == dp[c]*5) c++;
        }
        return dp[n-1];
    }
   
}

运行结果:

执行结果:通过

执行用时:2 ms, 在所有 Java 提交中击败了99.62%的用户

内存消耗:37.4 MB, 在所有 Java 提交中击败了73.38%的用户

此外还有最小堆算法:

要得到从小到大的第 nn 个丑数,可以使用最小堆实现。初始时堆为空。首先将最小的丑数 11 加入堆。每次取出堆顶元素 xx,则 xx 是堆中最小的丑数,由于 2x, 3x, 5x2x,3x,5x 也是丑数,因此将 2x, 3x, 5x2x,3x,5x 加入堆。

class Solution {
    public int nthUglyNumber(int n) {
        int[] factors = {2, 3, 5};
        Set<Long> seen = new HashSet<Long>();
        PriorityQueue<Long> heap = new PriorityQueue<Long>();
        seen.add(1L);
        heap.offer(1L);
        int ugly = 0;
        for (int i = 0; i < n; i++) {
            long curr = heap.poll();
            ugly = (int) curr;
            for (int factor : factors) {
                long next = curr * factor;
                if (seen.add(next)) {
                    heap.offer(next);
                }
            }
        }
        return ugly;
    }
}