264.丑数Ⅱ

给你一个整数 n ,请你找出并返回第 n 个 丑数 。
丑数 就是只包含质因数 2、3 和/或 5 的正整数。

示例 1:
输入:n = 10
输出:12
解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。
示例 2:
输入:n = 1
输出:1
解释:1 通常被视为丑数
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number-ii

在解答这道题目之前我们首先看看什么是丑数。如题目所说,丑数只包含质因数2、3或/和5,意为在质数2,3,5,7,11…中,丑数只能整除2,3,5,而合数4,6,8…则不受限制。由上述定义可知,任意丑数乘2,3或5仍为丑数,且对于任意丑数(除1外)可由一不相等的丑数乘2,3或5得到

如果不考虑时间复杂度,这道题思路就比较简单了。依次遍历所有整数,判断是否为丑数,直至找到第n个丑数为止。现在先使用方法Ⅰ(超出时间限制),即判断某整数是否丑数时依次将该数整除2,3或5,如整除后结果不为1,则继续除2,3或5,直至无法整除为止,最终结果是1则为丑数,不为1则不是丑数。这种直接判断的方法还有许多种,但由于时间复杂度过高基本都过不了测试。

然后我们再来看看优化的方法,首先是三指针法。丑数可由其他丑数乘2,3或5得到,所以我们可以用还没乘过2的最小丑数乘2,还没乘过3的最小丑数乘3,还没乘过5的最小丑数乘5,在其中取最小,得到新的丑数。使用这种方法我们需要三个指针i1,i2,i3,分别用来记录乘2、乘3、乘5的最小丑数的位置,当找到新丑数时对应的指针+1,具体代码如下:

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        res = [1]
        i2 = 0
        i3 = 0
        i5 = 0
        for i in range(1,n):
            ugly  = min(res[i2]*2,res[i3]*3,res[i5]*5)
            res.append(ugly)
            if(res[i] == res[i2]*2): i2 += 1
            if(res[i] == res[i3]*3): i3 += 1
            if(res[i] == res[i5]*5): i5 += 1
        return res[-1]

最后再介绍一种不算那么正规的方法,由上述定义可以推断丑数可写为2a*3b*5c,所以我们要求一定范围内的丑数,只需将2a,3b,5c尽可能的列出,使其全部分别相乘,即可得到一定范围内的全部丑数,但这种方法得到的丑数序列的后半段会缺少部分丑数,所以a,b,c要尽可能合理取值,代码如下:

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        res = [1]
        i2 = [2**a for a in range(1,35)]
        i3 = [3**a for a in range(1,20)]
        i5 = [5**a for a in range(1,15)]
        res = []
        ip = sorted(i2+i3+i5+[1])
        for i in range(len(ip)):
            for j in range(i+1):
                for q in range(j+1):
                    res += [ip[i]*ip[j]*ip[q]]
        res = set(res)
        res = sorted(list(res))
        return(res[n-1])

你可能感兴趣的:(每日一练)