uacs2024

导航

leetcode 264. 丑数 II

264. 丑数 II

暴力超时解🤡

class Solution {
public:
    int nthUglyNumber(int n) {
        if(n <= 6)  return n;
        n -= 6;
        int num = 7;
        while(n){
            int temp = num;           
            while(temp % 2 == 0)  temp /= 2;
            while(temp % 3 == 0)  temp /= 3;
            while(temp % 5 == 0)  temp /= 5;
            if(temp == 1) --n;
            ++num;
        }
        return num-1;
    }
};

 直接看题解

官方题解

法一:最小堆

class Solution {
public:
    int nthUglyNumber(int n) {
        // 定义一个包含质因数2、3、5的数组,这些质因数将用于生成丑数
        vector<int> factors = {2, 3, 5};
        // 创建一个集合,用于存储已经生成过的丑数,避免重复计算
        unordered_set<long> seen;
        // 创建一个优先队列(最小堆),用于存储和获取当前最小的丑数
        priority_queue<long, vector<long>, greater<long>> heap;
        // 将初始丑数1加入集合和优先队列中
        seen.insert(1L);
        heap.push(1L);
        // 初始化丑数变量,用于存储最终结果
        int ugly = 0;
        // 循环n次,每次获取当前最小的丑数,并生成新的丑数
        for (int i = 0; i < n; i++) {
            // 获取当前优先队列中的最小值
            long curr = heap.top();
            heap.pop();
            // 更新丑数变量为当前最小值
            ugly = (int)curr;
            // 遍历每个质因数,生成新的丑数
            for (int &factor : factors) {
                long next = curr * factor;
                // 如果新生成的丑数未被访问过,则加入集合和优先队列
                if (!seen.count(next)) {
                    seen.insert(next);
                    heap.push(next);
                }
            }
        }
        // 返回第n个丑数
        return ugly;
    }
};

 法二:动态规划

class Solution {
public:
//dp[i]肯定是其前面的某个数*2或*3*或*5得出来的
//而dp[i]*2,dp[i]*3,dp[i]*5 这三个数,肯定也是dp 数组后面某个位置的数
//可以推断,dp这个数组上的数,每个位置肯定都要x2\x3\x5 一遍,其结果是放在dp 数组后面某个位置
//那就可以从这个数组初始的状态dp[1]=1 开始,用p2\p3\p5 表示当前该哪个位置该乘以2\3\5 了
//只要每次取乘以 2、3、5 后的结果中最小的值,那这个最小的值就是最新一个的dp 值,然后相应地移动一下计算出这个新dp 值的 p2(或 p3 或p5)索引,即该下一个数去乘以2(或3 或5)了。
//按次遍历,计算出第i个数,即为dp[i]
    int nthUglyNumber(int n) {
        // 创建一个大小为n+1的动态规划数组,用于存储前n个丑数
        vector<int> dp(n + 1);
        // 初始化第一个丑数为1
        dp[1] = 1;
        // 定义三个指针,分别对应质因数2、3、5的当前索引位置
        int p2 = 1, p3 = 1, p5 = 1;
        // 从第2个丑数开始,直到第n个丑数
        for (int i = 2; i <= n; i++) {
            // 计算当前指针指向的丑数分别乘以2、3、5的结果
            int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
            // 当前新的丑数是这三个结果中的最小值
            dp[i] = min(min(num2, num3), num5);
            // 如果当前丑数是由num2得到的,则将p2指针后移一位
            if (dp[i] == num2)  p2++;         
            // 如果当前丑数是由num3得到的,则将p3指针后移一位
            if (dp[i] == num3)  p3++;
            // 如果当前丑数是由num5得到的,则将p5指针后移一位
            if (dp[i] == num5)  p5++;
        }
        // 返回第n个丑数
        return dp[n];
    }
};

 

posted on 2025-03-13 11:09  ᶜʸᵃⁿ  阅读(10)  评论(0)    收藏  举报