题目:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
解法:我们从上面可以知道丑数的质因子只有2,3,5三个,我们如果要知道从小到大排列的第N个丑数,可以使用暴力破解的方法:即逐个判断1,2,3,4,5,6,7,8,9.........等是不是丑数,直至找到第N个丑数为止,然后返回打印。但是暴力破解的方法的时间复杂度特别高。那么怎么降低时间复杂度呢?
我们先来看一下丑数的构成,即每一个丑数都是之前的丑数*2或者*3或者*5,因此后面的丑数都是之前丑数的倍数。
第一个丑数:1
第二个丑数是之前的丑数【1】*2或*3或*5中最小的那个,即1*2,1*3,1*5中最小的,因此第二个丑数为2.
第二个丑数:2
第三个丑数是之前的丑数【1,2】*2或*3或*5中最小的那个,即1*2,1*3,1*5,2*2,2*3,2*5中比已经保存的丑数大的同时在新产生的丑数中最小的,因此第三个丑数为3.(因为1*2为2,之前保存的丑数中最大的是2,因此不选择这个)
第三个丑数:3
以此类推。。。
第四个丑数:4
。。。。。。。。。
在知道丑数的构成原理以后我们就可以不用暴力穷举到产生N个丑数了,我们可以通过之前的丑数来产生新的丑数,不过我们的代价是需要一个N长的数组保存产生的丑数,从而方便新的丑数的生成,这种方法是空间换时间。
知道了原理以后我们的代码就很简单了,代码如下所示:
class Solution:
def GetUglyNumber_Solution(self, index):#index为N
# write code here
if index == 0:
return 0
if index == 1:
return 1
n = 1
ugly = [1]
while n < index:#逐步产生N个丑数
l_old = []
for i in ugly:
for j in [2,3,5]:
l_old.append(i*j)#l_old 添加了之前的丑数*2,*3,*5的所有丑数
cur_max = max(ugly)#之前丑数中最大的丑数,我们新加的丑数必须大于之前已经保存的最大的丑数
l_new = [x for x in l_old if x > cur_max]
ugly.append(min(l_new))#把新丑数加入丑数列表
n += 1
return ugly[index-1]#因为列表下表是从0开始的,所以第index个的下标是index-1