LintCode 4. 丑数 II

题目描述

设计一个算法,找出只含素因子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]

你可能感兴趣的:(LintCode 4. 丑数 II)