文巾解题 264. 丑数 II (剑指 Offer 49. 丑数)

这篇博客探讨了两种计算第n个丑数的方法:动态规划和最小堆。动态规划方法通过维护三个指针p2、p3和p5,有效地减少了空间复杂度,而最小堆方法虽然实现简单,但可能导致较高的空间和时间复杂度。两种方法都确保了正确性,并通过实例展示了计算过程。
摘要由CSDN通过智能技术生成

 

1 题目描述

2 解题方法

方法1:最小堆储存数组

同时设置一个集合存放我们已经考虑过的数,每看到一个丑数n,把2n,3n,5n放入这个最小堆。

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        lst=[1]
        ret=-1
        s={1}
        heapq.heapify(lst)
        while(n!=0):
            ret=heapq.heappop(lst)
            n=n-1
            if(2*ret not in s):
                s.add(2*ret)
                heapq.heappush(lst,2*ret)
            if(3*ret not in s):
                s.add(3*ret)
                heapq.heappush(lst,3*ret)
            if(5*ret not in s):
                s.add(5*ret)
                heapq.heappush(lst,5*ret)
            print(ret)
        return ret

 

方法2:动态规划

方法1使用动态堆的话,会预先存储较多的丑数,导致空间复杂度较高。同时,维护最小堆的话也会导致时间复杂度较高。

 

我们可以使用动态规划的方法:

定义数组dp,其中dp[i]表示第i个丑数(dp[1]=1)

如何得到其他的丑数呢?我们定义三个指针p2,p3,p5,表示下一个预备丑数是当前指针指向的丑数乘以对应的质因数(初始的时候,三个指针的数值都是1)。

对于后面的i,我们令dp[i]=min(dp[p2]*2,dp[p3]*3,dp[p5]*5),然后分别比较dp[i]和dp[p2]*2,dp[p3]*3,dp[p5]*5是否相等,如果相等则将对应的指针+1。(相等说明这个pi指针代表的数已经被考虑过了(要么是被自己对应的数,要么是被其他数))

 

正确性证明

计算d[i]的时候,指针px的含义是使得dp[j]*x>dp[i-1]的最小下标,即j>=px的时候,dp[j]*x>dp[i-1];j<px的时候,dp[j]*x<=dp[i-1]。

所以,在计算dp[i]的时候,dp[p2]*2,dp[p3]*3,dp[p5]*5都大于dp[i-1];同时dp[p2-1]*2,dp[p3-1]*3,dp[p5-1]*5都小于等于dp[i-1]。

令dp[i]=min(dp[p2]*2,dp[p3]*3,dp[p5]*5),那么这个就是大于dp[i-1]的最小丑数。

图解

1,一开始,dp[1]=1,三个指针都指向1。

2,计算dp[2],三个指针都指向1,所以分别乘以因子后是2,3,5;2最小,p2加一,dp[2]=2。

3 计算dp[3]

4 计算dp[4]

5 计算dp[5]

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        lst=[0,1]
        p2=1
        p3=1
        p5=1
        for i in range(2,n+1):
            lst.append(min(lst[p2]*2,lst[p3]*3,lst[p5]*5))
            if(lst[i]==lst[p2]*2):
                p2+=1
            if(lst[i]==lst[p3]*3):
                p3+=1
            if(lst[i]==lst[p5]*5):
                p5+=1
        return lst[n]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UQI-LIUWJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值