给你一个整数 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])