题目描述
设计一个算法,找出只含素因子2,3,5 的第 n 小的数。
符合条件的数如:1, 2, 3, 4, 5, 6, 8, 9, 10, 12...
测试样例
输入:9
输出:10
输入:1
输出:1
解题思路
说明下题目意思,序列中的数字只能是1、2、3、5的倍数(包含它们自身)。
1、堆
每次取出堆中最小的数,然后计算出其2倍、3倍以及5倍数,并加入到堆中,那么第n次取到的堆中最小数即第n小的数。
2、动态规划
在方法1中,每次都往堆中加入3个数字,并不知道它们之间的大小,如果我们每次都只加入下一个最小数,那么就可以节省查询最小值消耗的时间。
用一个有序数组dp记录前n个丑数,可以都初始化为1,因为第一个数必然是1。设置三个指针i2、i3和i5均指向dp中的元素,最小的丑数只可能出现在dp[i2]的2倍、dp[i3]的3倍以及dp[i5]的5倍三者之间。并且通过移动最小丑数对应的指针,就能保证生成的丑数序列是有序的。
时间复杂度:O(n)。生成一个丑数只需常量时间,所以生成n个丑数需要O(n)。
空间复杂度:O(n)。dp数组的长度为n。
代码
1、堆
import heapq
class Solution:
"""
@param n: An integer
@return: return a integer as description.
"""
def nthUglyNumber(self, n):
# write your code here
nums = [1]
visited = set([1])
# min_val是当前堆中最小的数
# 总共弹出n - 1次
for count in range(n - 1):
min_val = heapq.heappop(nums)
# 序列中的每个数都是其中某个数的2、3或5倍
for factor in (2, 3, 5):
if factor * min_val not in visited:
visited.add(factor * min_val)
heapq.heappush(nums, factor * min_val)
# 最后再弹出一次即第n小的数
return heapq.heappop(nums)
2、动态规划
class Solution:
"""
@param n: An integer
@return: return a integer as description.
"""
def nthUglyNumber(self, n):
# write your code here
dp = [1] * n
i2 = i3 = i5 = 0
for i in range(1, n):
# 序列中每个数(除1外)肯定是其中某个数的2、3或5倍
# 每次都取下一个最小的丑数加入序列,同时移动对应的指针
dp[i] = min(2 * dp[i2], 3 * dp[i3], 5 * dp[i5])
if dp[i] == 2 * dp[i2]:
i2 += 1
if dp[i] == 3 * dp[i3]:
i3 += 1
if dp[i] == 5 * dp[i5]:
i5 += 1
return dp[n - 1]
网友评论