Leetcode 264:丑数 II(超详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/88843985

编写一个程序,找出第 n 个丑数。

丑数就是只包含质因数 2, 3, 5正整数

示例:

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

说明:

  1. 1 是丑数。
  2. n 不超过1690。

解题思路

这个问题是之前问题Leetcode 263:丑数(超详细的解法!!!)的提高。这个问题首先可以想到通过暴力法解决,n不超过1690,那么我们可以将前1690个丑数全部找出来。这就很简单了,我们从1开始向float('inf')遍历,知道我们找到1690个丑数即可。

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        i, num = 0, 1
        uglys = list()
        
        while i < n:
            if self.isUgly(num):
                uglys.append(num)
                i += 1
            num += 1
            
        return uglys[n-1]
    
    def isUgly(self, num: int) -> bool:
        for p in [2, 3, 5]:
            while num and num%p == 0:
                num //= p
        return num == 1

但是上面这种做法会超时。我们其实有一个优雅的暴力解法,我们可以计算出第1690个丑数是2123366400,那么我们很容易的通过数学知识将1690个丑数都找到(丑数就是只包含质因数 2, 3, 5正整数)。

class Solution:
    ugly = sorted(2**a * 3**b * 5**c for a in range(32) for b in range(20) for c in range(14))
    
    def nthUglyNumber(self, n: int) -> int:
        return self.ugly[n - 1]

上面这种解法非常快,但是太取巧了。

我们希望有一个更好的办法,我们知道[1,2,3,4,5]是丑数,那么我们通过2,3,5乘上[1,2,3,4,5]就可以得到新的丑数,例如

(1) 1×2, 2×2, 3×2, 4×2, 5×2,(2) 1×3, 2×3, 3×3, 4×3, 5×3,(3) 1×5, 2×5, 3×5, 4×5, 5×5,

接着在通过2,3,5乘上新产生的丑数,那么又可以产生新的丑数。接着我们需要做的就是对上面的三行数进行归并排序。首先建立一个最小堆,然后将1加入堆中,此时堆中的最小元素就是1,将最小元素弹出。我们对最小元素乘上[2,3,5],将得到的值插入堆中,接着继续弹出下一个最小值,知道我们遍历完n个丑数。

import heapq
class Solution:
    def nthUglyNumber(self, n: int) -> int:
        q = [1]
        for _ in range(1, n):
            val = heapq.heappop(q)
            while q and q[0] == val:
                heapq.heappop(q)
            for i in [2, 3, 5]:
            	heapq.heappush(q, i*val)

        return q[0]

上面的这个代码真的非常优雅。当然你也可以手写三路归并

扫描二维码关注公众号,回复: 5733647 查看本文章
class Solution:
    def nthUglyNumber(self, n: int) -> int:
        ugly = [1] * n
        i2 = i3 = i5 = -1
        x = v2 = v3 = v5 = 1
        for k in range(n):
            x = min(v2, v3, v5)
            ugly[k] = x
            if x == v2:
                i2 += 1
                v2 = ugly[i2] * 2
            if x == v3:
                i3 += 1
                v3 = ugly[i3] * 3
            if x == v5:
                i5 += 1
                v5 = ugly[i5] * 5
        return x

reference:

https://www.geeksforgeeks.org/ugly-numbers/

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/88843985
今日推荐