这道题的题目可以描述为:我们只把包含因子2,3,5的数称为丑数。求按小到大的顺序的第1500个丑数。
根据丑数的定义,一个数如果能被2整除,则连续除以2;一个数如果能被3整除,则连续除以3;一个数如果能被5整除,则连续除以5。如果最后得到的结果是1就是丑数,然后按照顺序判断每个数是不是丑数即可。
代码如下:
int IsUgly(int number)
{
while (number % 2 == 0)
{
number /= 2;
}
while (number % 3 == 0)
{
number /= 3;
}
while (number % 5 == 0)
{
number /= 5;
}
return (number == 1) ? 1 : 0;
}
//求丑数1
int GetUglyNumber1(int index)
{
if (index <= 0)
{
return 0;
}
int number = 0;
int uglyFound = 0;
while (uglyFound < index)
{
++number;
if (IsUgly(number))
{
++uglyFound;
}
}
return number;
}
但这种算法实现时间效率低,有一部分时间花费在非丑数的整数上面。下面介绍另一种算法。首先创建一个数组,数组里面的数是已经排好的丑数,每一个丑数都是前面的乘以2、3或者5得到的。
这个数组中丑数按升序排放,并把已有最大的丑数记为M。对于生成下一个丑数,可以把已有的每个丑数乘以2,会得到一些小于,等于或大于M的数,对于小于或等于M的数不需要再考虑,其已在数组中有序排列。只需要第一个大于M的结果,将其记为M2。同样,把已有的丑数乘以3和5,都能得到第一个大于M的数M3和M5。那么下一个丑数就是M2,M3,M5里面最小的一个。
对于乘以2而言,肯定存在一个数T2,它之前的每一个数乘以2都小于M,它之后的肯定都大于M。我们标记这个位置,每次只需要给它之前的数乘以2,同时每次生成新的丑数的时候更新这个位置即可。同理对于3和5而言,也存在着T3和T5。
代码如下:
int Min(int number1, int number2, int number3)
{
int min = (number1 < number2) ? number1 : number2;
min = (min < number3) ? min : number3;
return min;
}
//求丑数2
int GetUglyNumber2(int index)
{
if (index <= 0)
{
return 0;
}
//用来存放丑数数组
int *puglyNubmers;
puglyNubmers = (int*)malloc(sizeof(int)*index);
if (puglyNubmers != NULL)
{
for (int i = 0; i < index; i++)
{
*(puglyNubmers + i) = 0;
}
}
*puglyNubmers = 1;
//下一个生成的丑数
int nextUglyIndex = 1;
//即T2(T2*2==目前数组中最大的丑数)
int *pMultiply2 = puglyNubmers;
//T3
int *pMultiply3 = puglyNubmers;
//T4
int *pMultiply5 = puglyNubmers;
while (nextUglyIndex < index)
{
int min = Min(*pMultiply2 * 2, *pMultiply3 * 3, *pMultiply5 * 5);
puglyNubmers[nextUglyIndex] = min;
while (*pMultiply2 * 2 <= puglyNubmers[nextUglyIndex])
{
++pMultiply2;
}
while (*pMultiply3 *3 <= puglyNubmers[nextUglyIndex])
{
++pMultiply3;
}
while (*pMultiply5 * 5 <=puglyNubmers[nextUglyIndex])
{
++pMultiply5;
}
++nextUglyIndex;
}
int ugly = puglyNubmers[nextUglyIndex-1];
free(puglyNubmers);
puglyNubmers = NULL;
return ugly;
}