我们把只包含因子2、3和5的数称为丑数(Ugly Number)。求从小到大的顺序的第1500个丑数。习惯上我们把1当做第一个丑数。
这道题暴力的解法就是按照顺序检查每一个数是不是丑数。
判断一个数是不是丑数的函数如下:
bool IsUglyNumber(int num) { while(num%2==0) num/=2; while(num%3==0) num/=3; while(num%5==0) num/=5; returnnum==1?true:false; }
从1开始,按顺序检查,如果这个数是丑数,加1,直到1500个丑数为止。
int GetUglyNumber1(int index) { if(index<1) return0; intnumber=0; intcount=0; while(count<index) { number++; if(IsUglyNumber(number)) ++count; } returnnumber; }
这个代码非常整洁,但最大的问题每一个整数都需要计算。即使这个数字不是丑数,我们还是需要对它进行求余和除法操作。该算法的效率是很低的。
我们应该试着找到一种只需要计算丑数的方法,而不需要在非丑数的整数上面花费时间。根据丑数的定义,丑数应该是另一个丑数乘以2、3、5的结果(1除外)。因此我们可以创建一个数组,里面的数字是排好序的丑数,每一个丑数都是前面的丑数乘以2、3或者5得到。
int min(int a,int b,int c) { intmin=a<b?a:b; returnmin<c?min:c; } int GetUglyNumber2(int index) { if(index<1) return0; int*pUglyNumbers=new int[index]; pUglyNumbers[0]=1; intnextIndex=1; int*pUgly2=pUglyNumbers; int*pUgly3=pUglyNumbers; int*pUgly5=pUglyNumbers; while(nextIndex<index) { pUglyNumbers[nextIndex]=min(*pUgly2*2,*pUgly3*3,*pUgly5*5); while(*pUgly2*2<=pUglyNumbers[nextIndex]) ++pUgly2; while(*pUgly3*3<=pUglyNumbers[nextIndex]) ++pUgly3; while(*pUgly5*5<=pUglyNumbers[nextIndex]) ++pUgly5; ++nextIndex; } intugly=pUglyNumbers[nextIndex-1]; delete[]pUglyNumbers; //将数组内存释放掉 returnugly; }
这种方法需要一定的内存空间,是一种以空间换时间的思想。