题目: 题目:把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
设计一个算法,找出只含素因子2,3,5 的第 n 小的数。符合条件的数如:1, 2, 3, 4, 5, 6, 8, 9, 10, 12…
思路:
思路1:从1开始递增,依次判断每个数是否是丑数,不够高效;
思路2:思路1之所以效率低,比较关键的一点是遍历的每一个数字都进行丑数判断。思路2不是去判断丑数,而是计算出丑数:因为每个丑数都可以看成是由1去乘以2、3、5,再乘以2、3、5而衍生出来的。可以用三个指针指向第一个丑数1,三个指针分别表示乘2,乘3,乘5,将三个指针计算出来的最小的丑数放在数组中,并将该指针向后移动一个位置。为了得到第1500个丑数,需要一个长度1500的数组来记录已经计算出来的丑数。因此这个思路也可以说是用空间换时间。
基于以上思路,java参考代码如下:
public class GetUglyNumber_Solution {
//思路一:判断每个数是否是丑数
public static int getUglyNumber(int num){
if(num<=0)
return 0;
int number = 0,uglyFound = 0;
while (uglyFound<num){
number++;
if(isUgly(number))
uglyFound++;
}
return number;
}
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;
}
//思路二:用空间换时间
public static int getUglyNumber2(int n) {
if(n<=0)
return 0;
if(n==1)
return 1;
int[] nums = new int[n];
nums[0] = 1;
//用三个指针指向第一个丑数1,三个指针分别表示乘2,乘3,乘5,
//将三个指针计算出来的最小的丑数放在数组中,并将该指针向后移动一个位置
int p2 = 0,p3 = 0,p5 = 0;
for(int i=1;i<n;i++){
nums[i] = Math.min(nums[p2]*2,Math.min(nums[p3]*3,nums[p5]*5));
// //2*3=6,3*2=6,会有重复值,因此下面需要使用if,而不能用if-else
if(nums[i]==nums[p2]*2) p2++;
if(nums[i]==nums[p3]*3) p3++;
if(nums[i]==nums[p5]*5) p5++;
}
return nums[n-1];
}
public static void main(String[] args) {
System.out.println(getUglyNumber(10));
System.out.println(getUglyNumber2(10));
}
}
测试用例:
a.功能测试(输入2,3,4,5,6等)。
b.特殊输入测试(边界值1;无效输入0)。
c.性能测试(输入较大的数字,如1500)。
参考:
https://www.jianshu.com/p/75bd206d865d
https://www.cnblogs.com/hglibin/p/9030315.html