求第K个丑数

来源:互联网 发布:银联数据 编辑:程序博客网 时间:2024/06/06 05:48

首先,我们来看下这道面试题的描述:

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。


法一:遍历法

要求第K个丑数,那么根据它的性质(只含有2,3,5的因子),我们可以想到一种很直观的方法:
从1开始每次加一往后找,知道找到K个丑数,每一次判断该数是否为丑数的方法是——看该数是否能被2整除,若能则一直除2;然后再看能否被3整除,若能则一直出3;5也做同样的处理。这样看最后剩下的数是否为1,若为1则该数是丑数。

于是我们可以很快写出如下代码:

 int GetUglyNumber_Solution(int index)  {        if(index == 1)            {                 return 1;            }        int start = 1;        for(int i = 2; i <= index; ++i)            {                start++;                while(!IsUglyNum(start))                    {                        start++;                    }            }        return start;    }    bool IsUglyNum(int num)        {            while(num % 2 == 0)                {                    num /= 2;                }            while(num % 3 == 0)                {                    num /= 3;                }            while(num % 5 == 0)                {                    num /= 5;                }            if(num != 1)                {                    return false;                }            return true;        }

在本地一跑,结果一般会对着,但是当你把输入的数比较大时,如1500,那么你会发现:结果要等上个5~6秒的样子。然后在OJ上提交,会发现根本通不过,超时。显然,时间复杂度太高。那么该如何优化呢,当然是我们的空间换时间,这类的题都这样去想就OK了。下面看第二种方法。


法二:动态规划

*算法分析:*
用一个表table,把0到K-1个丑数存起来,然后求第K个丑数时,可以用前面求出来的丑数,做一个遍历,分别计算该丑数乘以2,3,5是否大于第K-1个丑数的值,取最小的那个大于K-1的数,必定为第K个丑数。

但是这一块的难点在于:在table中找min时的逻辑处理,这一块很难讲清楚,需要看官自己去理清楚。举个例子,在求第4个丑数时,按照算法,我们会先求得1X2,1X3, 1X5,然后这时候5已经大于第3个丑数了;但是我们会发现这时候还不能出循环,因为 接下来2X2也大于第3个丑数,而且4小于5。那么在得到的min为某个丑数乘以3或者5得到时我们还要继续往后找,看是否下一个丑数乘以2,或3 比它更小。 代码如下:

    int GetUglyNumber_Solution(int index)     {           vector<int> table;        table.push_back(1);        if(index == 1)            {                return 1;            }        for(int k  = 2; k <= index; ++k )        {               int min = INT_MAX;            for(int i = 0; i < k-1; ++i)  //table 的下标                {                    if(table[i] * 2 > table[k-2])                        {                            if(table[i] * 2 < min)                                {                                    min = table[i] * 2;                                }                            break;                        }                    else if(table[i] * 3 > table[k - 2])                        {                            if(table[i] * 3 < min)                                {                                    min = table[i] * 3;                                }                        }                    else if(table[i] * 5 > table[k -2])                        {                            if(table[i] * 5 < min)                                {                                    min = table[i] * 5;                                }                        }                }            table.push_back(min);         }        return table[index-1];    }

当我们输入1500时大概只要4ms就可出结果了。

原创粉丝点击