1.题目
2.思路
1.首先一个数要可以被2,3,5其中的1个或者多个整除, 接着该数除以2, 3, 5, 获得的商是不是在2, 3, 5中,如果不是,那么它肯定不是丑数,这种思路是错误的,比如12,它由
2x6构成,除以一次2获得商为6,不在,就判断为丑数了,肯定是错误的,应该继续除以2。
2.所以判断是不是丑数的思路是
public static boolean isUglyNumber(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;
}
3.使用以上方法做的话,不管是不是丑数,都会判断一下,所以我们在这里只判断丑数,对非丑数不再判断。一个新的丑数肯定是由下面的方式计算出来的:
丑数 = 丑数 * 2
丑数 = 丑数 * 3
丑数 = 丑数 * 5
例如:1, 分别乘以2、3、5,获得2, 3, 5, 为了保证从小到大顺序,我们只取里面的最小值2(把这些数都选上的话,会漏掉4),接着1 2 ,如果继续分别乘以 2 3 5 获得
2 4
3 6
5 10
我们选择第一个大于已有丑数最大值的数字,4, 3, 5, 选择最小值 3,
可以发现刚才上面计算出来的2,其实第一次计算的时候已经通过1 * 2得到了,所以没必要再计算一次,所以应该直接从2开始乘。
4、所以我设置三个指针来指向开始乘 2 、 3、 5的位置
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index <= 0) return 0;
// 乘以2、3、5的开始位置
int p2 = 0, p3 = 0, p5 = 0;
int[] result = new int[index];
result[0] = 1;
for(int i = 1; i < index; i++){
// 找到2、3、5中的最小值
result[i] = Math.min(Math.min(result[p2] * 2, result[p3] * 3),
result[p5] * 5);
// 移动指针到下一次该乘的位置
if(result[i] == result[p2] * 2) ++p2;
if(result[i] == result[p3] * 3) ++p3;
if(result[i] == result[p5] * 5) ++p5;
}
return result[index-1];
}
}
灵活应用了丑数的定义和位置指针
时间复杂度为O(n)
以空间换了时间(创建了数组)