剑指offer 49. 丑数

题目详解

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

输入:n = 10
输出:12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
暴力解法

最简单的思路是暴力了!!!把所有在范围内的丑数都列举出来,然后去重+排序。然而妥妥的超出时间限制。

class Solution(object):
    def nthUglyNumber(self, n):
        Set = set()
        for i in range(n):
            for j in range(int(math.log(pow(2,n-i),3))+1):
                for k in range(int(math.log(pow(2,n-i)//pow(3,j),5))+1):
                    x = pow(2,i)*pow(3,j)*pow(5,k)
                    Set.add(x)
        List = list(Set)
        List.sort()
        return List[n-1]
动态规划+ 二分法

设立一个数组dp,假设里面保存了N个排好序的丑数。那么第N+1个丑数就必定来自于dp * 2 , dp * 3, dp * 5中产生的。比如说有丑数序列dp[1, 2 , 3, 5 ] ,那么第N+1个丑数肯定在这三个数组中,找到这三个数组中大于5的最小数。三个数组得到的分别是[6, 6,10],由此而知下一个数就是6了。总的时间复杂度为O(N^2)或者O(NlogN)。

Num2 = [ 1*2, 2*2, 3*2, 5*2]
Num3 = [ 1*3, 2*3, 3*3, 5*3]
Num5 = [ 1*5, 2*5, 3*5, 5*5]
动态规划+ 三指针

上面的方法做了很多重复的工作,由于dp前面的数是固定不变的,没必要每次都乘以2, 3, 5。

  1. 我们只需要保存p2, p3, p5这三个指针,三个指针分别代表该丑数等待被 * 2 ,* 3, * 5, 或者说是该丑数是否通过* 2, * 3 ,* 5产生过新丑数的标识,每个数三个指针三个标识,用完即用来白标识别的数,就这三个标识一直复用。)
  2. 当一个丑数已经被* 2, * 3, * 5后,对于生成丑数已经没有用了,我们把对应指针前移一位,让下一个丑数等待被*来生成新丑数。
  3. 每次计算出来个三个丑数的最小的一个作为新丑数加入,然后判断是通过 * 多少得到的来后移对应指针。
    通过123我们可以发现,我们每次生成的都是最小的丑数(保证是升序),并且每个丑数都尝试过被 *2 *3 *5(保证无遗漏)。
class Solution(object):
    def nthUglyNumber(self, n):
        p2 = 0
        p3 = 0
        p5 = 0
        List = [1]
        while len(List)<n:
            List.append(min(List[p2]*2,List[p3]*3,List[p5]*5))
            # 这里是用if, if, if。 而不是if else。 用来去重
            if List[p2]*2==List[-1]:
                p2 +=1
            if List[p3]*3==List[-1]:
                p3 += 1
            if List[p5]*5==List[-1]:
                p5 += 1
        return List[n-1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值