方法一:暴力法
代码如下:
判断是否是丑数
public static boolean isUgly(int n){
while(n!=1){
if(n%2 == 0){
n /= 2;
}else if(n%3 == 0){
n /= 3;
}else if(n%5 == 0){
n /= 5;
}else{
break;
}
}
return n==1;
}
public static int getUglyNumber(int n){
if(n == 0) return 0;
int count = 0;
for(int i = 1;i<Integer.MAX_VALUE;i++){
if(isUgly(i))
count++;
if(count == n)
return i;
}
return 0;
}
方法二:思路:
三指针法。只计算丑数,而不计算非丑数。丑数=丑数*(2/3/5),所以创建数组保存有序的丑数。
关键在于如何在计算丑数的过程中保持数组有序。当前的丑数必然是之前某一个丑数*因子的结果,
但是不需要每个数都要乘一遍2、3、5。要获得的丑数必然是大于现在已有的,
在计算得出丑数中选择一个最小的放入数组中,来保持数组的有序,因为新放入的丑数是根据之前的丑数计算得到的,
所以必然是有序的。为了每次新得到的三个丑数都是比已有丑数大,且最小,所以要记录各个因子下次计算要使用的已有丑数在什么位置,
否则就会出现跳数,比如已有{1,2,3,4},我们知道下一个丑数应该是5,但是如果因子5没有选择第一个丑数1来相乘,就会漏掉5这个丑数。 代码实现如下:
public static int getUglyNumber(int n) {
if(n == 0) return 0;
//定义三个指针,分别指向质因子2,3,5
int a = 0;
int b = 0;
int c = 0;
int[] arr = new int[n];
arr[0] = 1;
for(int i = 1;i<n;i++){
int r = arr[a]*2;
int s = arr[b]*3;
int t = arr[c]*5;
int sign = Math.min(r,Math.min(s,t));
//将最小的丑数放入结果集中,用于下一次计算
arr[i] = sign;
//找出对应此次计算最小丑数的因子,并移动指针指向下一次计算丑数对应的老丑数下标
if(sign%2==0){
a++;
}
if(sign%3==0){
b++;
}
if(sign%5==0){
c++;
}
}
return arr[n-1];
}