49. 丑数

本文介绍了如何使用动态规划和小根堆算法解决LeetCode中的剑指Offer问题49——找到第n+1个丑数。通过理解丑数的定义和递推性质,利用三个指针分别跟踪乘以2、3和5的最小丑数,实现了O(n)和O(n*logn)两种时间复杂度的解决方案。
摘要由CSDN通过智能技术生成
剑指 Offer 49. 丑数

思路:动态规划

设已知长度为n的丑数序列 x 1 , x 2 , x 3 , ⋯   , x n x_1,x_2,x_3,\cdots,x_n x1,x2,x3,,xn,求第n+1个丑数,根据递推性质,丑数 x n + 1 x_{n+1} xn+1只可能为:
f ( x ) = { x a × 2 a ∈ [ 1 , n ] x b × 3 b ∈ [ 1 , n ] x c × 5 c ∈ [ 1 , n ] f(x)=\begin{cases} x_a\times2 & {a\in[1,n]}\\ x_b\times3 & {b\in[1,n]}\\ x_c\times5 & {c\in[1,n]} \end{cases} f(x)=xa×2xb×3xc×5a[1,n]b[1,n]c[1,n]
丑数递推公式为:

x n + 1 = m i n ( x a × 2 , x b × 3 , x c × 5 ) x_{n+1}=min(x_a\times2,x_b\times3,x_c\times5) xn+1=min(xa×2,xb×3,xc×5)

由于 x n + 1 x_{n+1} xn+1是最接近 x n x_n xn的丑数,因此索引a, b, c满足以下条件:
{ x a × 2 > x n ≥ x a − 1 × 2 即 x a 为 首 个 乘 以 2 后 大 于 x n 的 丑 数 x b × 3 > x n ≥ x b − 1 × 3 即 x b 为 首 个 乘 以 3 后 大 于 x n 的 丑 数 x c × 5 > x n ≥ x c − 1 × 5 即 x c 为 首 个 乘 以 5 后 大 于 x n 的 丑 数 \begin{cases} x_a\times2>x_n\ge x_{a-1}\times2 &即x_a为首个乘以2后大于x_n的丑数\\ x_b\times3>x_n\ge x_{b-1}\times3 &即x_b为首个乘以3后大于x_n的丑数\\ x_c\times5>x_n\ge x_{c-1}\times5 &即x_c为首个乘以5后大于x_n的丑数 \end{cases} xa×2>xnxa1×2xb×3>xnxb1×3xc×5>xnxc1×5xa2xnxb3xnxc5xn
因此,设置指针a,b,c指向首个丑数,循环递推公式得到下个丑数,并每轮将对应指针+1

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> dp(n);
        dp[0]=1;
        int a=0,b=0,c=0;
        for(int i=1;i<n;++i){
            int na=dp[a]*2;
            int nb=dp[b]*3;
            int nc=dp[c]*5;
            dp[i]=min(na,min(nb,nc));
            if(dp[i]==na)++a;
            if(dp[i]==nb)++b;
            if(dp[i]==nc)++c;
        }
        return dp[n-1];
    }
};

时间复杂度 O(n)

空间复杂度 O(n)

思路:小根堆+哈希表去重

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> factors={2,3,5};
        unordered_set<long> seen;
        priority_queue<long,vector<long>,greater<long>> heap;
        seen.insert(1L);
        heap.push(1L);
        int ugly=0;
        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);
                }
            }
        }
        return ugly;
    }
};

时间复杂度 O(n*logn)

空间复杂度 O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值