LintCode刷题 4. 丑数 II

438 阅读4分钟

原题链接:

http://www.lintcode.com/zh-cn/problem/ugly-number-ii/

题目描述

设计一个算法,找出只含素因子2,3,5 的第 n 小的数。

符合条件的数如:1, 2, 3, 4, 5, 6, 8, 9, 10, 12...

注意事项

我们可以认为1也是一个丑数

样例

如果n = 9, 返回 10

题目解析:

题目给出了丑数的定义,是想要我们用一个算法找出丑数。

思路

思路一

一个比较简单的思路是,从小到大遍历整数,然后判断该数是不是丑数。 问题就在于,如何判断该数是不是丑数? 根据定义,丑数是只含有2,3,5因子的数,也就是说丑数是由m个2,n个3,k个5相乘得到。那么,丑数就一定能被2、3、5中的一个或者多个整除。并且整除下去,直到不能整除为止,最终得出来的结果就一定是1。

值得一说的是,这种方法思路上是没问题的,但是时间过长,程序会报超时。

思路二

直接根据定义来找到丑数,ugly=(m*2)*(n*3)*(k*5)。定义很简单,问题是将得出来的丑数从小到大排列。 这里比较用语言来表达出来。先上代码

    ugly2 = uglyList[num_2]*2
    ugly3 = uglyList[num_3]*3
    ugly5 = uglyList[num_5]*5
    
    ugly = min(ugly2,ugly3,ugly5)

第一个丑数为1,然后第二个丑数就从1*2=2,1*3=3,1*5=5中最小的那个数取得。显然是2.这时,丑数数组就是[1,2]。

然后呢,需要从2*2=4,1*3=3,1*5=5中取最小的那个数3.此时。丑数数组为[1,2,3].

接着,从2*2=4,2*3=6,1*5=5中取最小的4,此时丑数数组为[1,2,3,4]。

接着,从3*2=6,2*3=6,1*5=5中取最小的5.此时丑数数组为[1,2,3,4,5]。

看到规律了吗? 丑数数组中,每个丑数乘以2,乘以3,乘以5得出的新的数都是丑数。那么,我们就将数组中第一个丑数乘以2,只要乘以2的数被选取进了丑数数组,那么就到当前乘以2的那个丑数的下一个丑数乘以2,也就是上面的num_2这个下标+1。乘以3和乘以5都是相似的。最终从得出来的新丑数ugly2,ugly3,ugly5中选取最小的那个丑数放入丑数数组。以此类推。

这里需要注意的是, 有可能ugly2,ugly3,ugly5会相等。所以,需要判断下是否跟这3个数的哪个相等,只要相等,就将其下标+1.

代码(Python)

思路一代码:

 """
    @param n: An integer
    @return: the nth prime number as description.
    """
    def nthUglyNumber(self, n):
        # write your code here
        if n == 1:
            return 1
        
        #第count个丑数
        count = 1
        #从2遍历到无穷
        num = 2
        
        while(count < n):
            
            tempNum = num
            #如果能被2整除,那就除2
            while(tempNum % 2 == 0):
                tempNum = tempNum/2
                
            while(tempNum % 3 == 0):
                tempNum = tempNum / 3
                
            while(tempNum % 5 == 0):
                tempNum = tempNum / 5
            
            #整除过后,结果为1.代表是丑数    
            if tempNum == 1:
                count += 1
            
            #第n个参数,返回结果    
            if count == n:
                return num
            
            num += 1

思路二代码:

 """
    @param n: An integer
    @return: the nth prime number as description.
    """
    def nthUglyNumber1(self, n):
        if n == 1:
            return 1
        
        #存放丑数的数组    
        uglyList = [1]
        
        #当前丑数数组中,当前要乘以2那个丑数在数组中的位置。
        #丑数数组中的所有丑数,乘以2之后,都是丑数,所以每个丑数都需要乘以2。
        #但是乘以2之后,新的数加入了丑数数组,num_2就要加1,让下一个数乘以2
        num_2 = 0
        num_3 = 0
        num_5 = 0
        
        for i in  range(1,n):
            
            
            ugly2 = uglyList[num_2]*2
            ugly3 = uglyList[num_3]*3
            ugly5 = uglyList[num_5]*5
            
            #取最小值放入丑数数组
            ugly = min(ugly2,ugly3,ugly5)
            #print "ugly =",ugly
            uglyList.append(ugly)
            
            #如果新的丑数是由乘以2、或者3、或5得来,那么需要将对应的下标加1
            #注意这里有可能会出现ugly与其中两个数都相等的情况
            if ugly == ugly2:
                num_2 += 1
            if ugly == ugly3:
                num_3 += 1
            if ugly == ugly5:
                num_5 += 1
        
        #print "uglyList=",uglyList        
        return uglyList[-1]

谦言忘语

个人目前只懂一丁点python语法,所以不做语法上的优化,而且整体代码风格效果会尽量跟C语言趋于一致。