版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013132035/article/details/81462270
题目:
我们把只包含因子2、3和5的数称作丑数(Ugly Number)。求按从小到大的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做第一个丑数。
第一思路:逐个判断每个整数是不是丑数的解法,直观但不高效。
注:所谓一个数m是另一个数n的因子,是指n能被m整除,也就是n%m == 0。
根据丑数的定义,丑数只能被2、3和5整除。即一个数能被2整除,我们把它连续除以2;如果能被3整除,就连续除以3;如果能被5整除,就连续除以5,直到最后如归我们得到的是1,那么这个数就是丑数,否则不是。
代码实现:
public class Main {
//判断一个数是不是丑数
public static boolean isUgly(int number){
while(number % 2 == 0){
number /= 2;
}
while(number % 3 == 0){
number /= 3;
}
while(number % 5 == 0){
number /= 5;
}
return (number == 1) ? true : false;
}
//从1开始寻找第1500个丑数
public static int getUglyNumber(int index){
if(index < 0){
return 0;
}
int number = 0;
int uglyFound = 0;
while(uglyFound < index){
++number;
if(isUgly(number)){
++uglyFound;
}
}
return number;
}
public static void main(String[] args) {
int ugNum = getUglyNumber(1500);
System.out.println(ugNum);
}
}
缺点:
效率比较低,时间复杂度比较大。因为其对每一个数都进行了计算(不管是不是丑数,故影响其效率)。
第二思路:创建数组保存已经找到的丑数,用空间换时间的解法
由丑数的定义:丑数应该是另一个丑数乘以2、3或者5的结果(1除外)。因此我们可以创建一个数组,里面的数字是排好序的丑数,每一个丑数都是前面的丑数乘以2、3或者5得到的。直观的优化措施就是看我们能不能降低时间复杂度,即只在丑数上花时间,而不在非丑数上浪费时间。故根据上面的丑数定义和思路,我们开辟O(n)的空间来得到时间复杂度为O(n)的算法。
代码实现:
public class Main1 {
public static int getUglyNumber(int index){
if(index <= 0){
return 0;
}
List<Integer> list = new ArrayList<Integer>();
list.add(1);
int m2 = 0, m3 = 0, m5 = 0, i2 = 0, i3 = 0, i5 = 0, min = 0;
while(list.size() < index){
m2 = list.get(i2) * 2;
m3 = list.get(i3) * 3;
m5 = list.get(i5) * 5;
min = Math.min(m2, Math.min(m3, m5));
list.add(min);
if(min == m2){
++i2;
}
if(min == m3){
++i3;
}
if(min == m5){
++i5;
}
}
return list.get(index-1);
}
public static void main(String[] args) {
System.out.println(getUglyNumber(1500));
}
}
小结:
第二种以较小的空间换取时间的做法使得算法的效率明显提升。因为其每一步的计算都是在丑数上做计算,并且其计算的丑数是一步到位,而第一个算法其一是不是丑数都进行了计算,其二其while()循环增加了时间复杂度。