题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。求按从小到大的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做第一个丑数。
思路:
直观思路:从1开始逐一判断每个整数是否为丑数,直到找到第n个丑数,时间效率太低。因为对于每一个整数都要计算,即使一个整数不是丑数,也要进行除法和取余操作。
空间换时间的解法:
创建数组存放已经排序好的丑数,这将消耗一定的内存开销。关键是怎样确保数组里的丑数是有序的。根据丑数的定义,丑数应该是另一个丑数的2、3或者5倍的结果,因此,我们从数组中已有的丑数里找到三个丑数T2、T3、T5,它们分别和2、3、5相乘得到的值恰好比已有的最大丑数大,三个乘积中最小的一个就是下一个丑数,存放入数组中,同时更新T2、T3、T5,使它们仍然保持与2、3、5的乘积恰好比已有的最大丑数大。这种思路不需要在非丑数上进行计算,时间复杂度较低。
考点:以空间换时间
实现:
public int GetUglyNumber_Solution(int index) {
if(index<=0) return 0;
int[] ugly = new int[index];
ugly[0] = 1;
int count = 1;
int T2 = 0;
int T3 = 0;
int T5 = 0;
while(count<index){
ugly[count++] = getMinimum(ugly[T2]*2,ugly[T3]*3,ugly[T5]*5);
if (ugly[T2]*2==ugly[count-1])
T2++;
if (ugly[T3]*3==ugly[count-1])
T3++;
if (ugly[T5]*5==ugly[count-1])
T5++;
}
return ugly[count-1];
}
private int getMinimum(int a,int b,int c){
if(a>b)
a=b;
if(a>c)
a=c;
return a;
}
/*逐一判断每个数是否为丑数,效率太低
public int GetUglyNumber_Solution1(int index) {
if(index<=0)return 0;
int count = 0;
int number = 0;
while(count<index){
number++;
if(isUgly(number)){
count++;
}
}
return number;
}
public boolean isUgly(int data){
while(data%2==0){
data = data/2;
}
while(data%3==0){
data = data/3;
}
while(data%5==0){
data = data/5;
}
if(data == 1){
return true;
}else{
return false;
}
}
收获:
- 判断m是否为n的因子:即判断n能否被m整除,也就是n%m=0。要掌握判断因子的方法。例如判断丑数的程序如下:
public boolean isUgly(int data){
while(data%2==0){
data = data/2;
}
while(data%3==0){
data = data/3;
}
while(data%5==0){
data = data/5;
}
if(data == 1){
return true;
}else{
return false;
}
}
2.丑数是另一个丑数的2、3或者5倍,要记住这类特性和规律。特别是在遇到类似的新概念时。