题目:我们把只包含因子2、3、5的数称作丑数。求按从小到大的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做第一个丑数。
思路:(1)只包含因子2、3、5,那么用2、3、5除以后必定为1,可以作为丑数的判定标准。从1开始递增数字,每个数都判断是不是丑数,直到找到1500个。这种方法有很大的盲目性,每个数都不断的除以2、3、5效率非常低。
(2)不去判断一个数是不是丑数,而是找出下一个丑数。一个丑数它必定是前面的丑数乘上2或3或5得来的(为什么这样说?因为如果它不是前面的丑数乘上2或3或5,而是乘别的数得来的,那么说明他除了2、3、5还有别的因子,不符合丑数的定义),那么我们每次生成下一个丑数,直到生成1500个。那么被乘的前一个丑数如何确定?它应该满足乘上2或3或5之后刚好比当前已经生成的最大的丑数还要大,而且对2、3、5而言每一个数前面的丑数都是不一样的,每次生成一个丑数即需要更新乘数的位置。
这种算法只花费了额外的一点空间,遍历1500次,每次遍历移动了乘数的的几个指针,比思路1的方法要快得多。
实现代码:
int GetUglyNumber(int n)
{
if(n < 0)
return 0;
int* UglyNumbers = new int[n];
UglyNumbers[0] = 1;
int* Multiply2 = UglyNumbers;
int* Multiply3 = UglyNumbers;
int* Multiply5 = UglyNumbers;
int NextUglyIndex = 1;
while(NextUglyIndex < n)
{
UglyNumbers[NextUglyIndex] = Min(*Multiply2 * 2, *Multiply3 * 3, *Multiply5 * 5);
while(*Multiply2 * 2 <= UglyNumbers[NextUglyIndex])
++Multiply2;
while(*Multiply3 * 3 <= UglyNumbers[NextUglyIndex])
++Multiply3;
while(*Multiply5 * 5 <= UglyNumbers[NextUglyIndex])
++Multiply5;
++NextUglyIndex;
}
int ugly = UglyNumbers[NextUglyIndex - 1];
delete[] UglyNumbers;
return ugly;
}
int Min(int a, int b, int c)
{
int tmp = a < b ? a : b;
return tmp < c ? tmp : c;
}