寻找丑数
问题描述: 我们把只包含因子2、3和5的数称为丑数。例如6、8都是丑数,但是14不是,因为它包含因子7.
习惯上我们把1当作是第一个丑数。求按从小到大的顺序的第1500个丑数。
算法思路:
方法1 暴力求解
从1开始逐个遍历整数,每个整数如果包含2、3和5中的任何一个因子就除以该因子(包含多个就除以多个,直到不含2、3和5这三个因子),如果这样除得的结果为1,则表示只包含2、3和5,为丑数,此时丑数个数加1,直到个数为1500个。
缺点是:效率低,不管一个数是不是丑数都要作计算。
例如:第 1500 个丑数是 859963392,那么我们需要从 1 开始枚举到 859963392。
方法2
只计算丑数,后面的丑数根据前面的丑数和2、3、5来得出。
因为丑数的因子只有 2 3 或者 5,所以丑数必定是 某个丑数 k 的 2倍、3倍、或者 5倍。
这样我们就不需要从 1 开始枚举了到第 num 个丑数 target,我们可以根据得到丑数来推导出下一个丑数,这样大大节省了时间,接下来就是该如何去找到 这个 丑数 k 。
我们需要一个辅助数组 arr 来存储我们找到的丑数,最笨的方法当然是每次从数组的第一个开始找 k ,使得它的 2倍 3倍 或者 5倍 大于当前的数组最大值。
package com.bean.algorithmexec;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class UglyNumberDemo {
/* * 把只包含因子2、3和5的数称作丑数(Ugly Number)。 * 例如6、8都是丑数,但14不是,因为它包含因子7。 * 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 * */
/* * 思路分析: * 丑数应该是另一个丑数乘以2、3、5得到的。也就是说,根据一个丑数,可以计算出它乘以2、3、5得到的丑数。 * 因此,可以初始化一个数组numberArray,用于保存已经找到的丑数。 * 然后按序用数组里的数,乘以2、3、5得到新的丑数,并加入到数组中。 * * 首先将第一个丑数1加入的数组中。 * 然后计算1*2、1*3、1*5的最小值,并把最小值加入到数组中。 * 显然,1*2得到的值最小,所以把2加入到数组中。 * 当前数组为[1、2]。 * 因为这个2是由1*2计算得到的,所以下一次计算时,就不能再计算1*2了,不然2始终是最小值。 * 下一次应该计算2*2。或者说,由于1已经乘过2了,还有3、5没有乘,所以不用再乘2了,因为1不能多次乘2,以免得到重复的2。 * */
public static int getUglyNumber(int n) {
if(n <= 0) return 0;
int[] numberArray = new int[n];
numberArray[0] = 1;
int i = 0, j = 0, k = 0; // 分别代表2,3,5的下标
for(int a = 1; a < n; a++) {
int p = numberArray[i] << 1;
int q = numberArray[j] * 3;
int r = numberArray[k] * 5;
int min = Math.min(p, Math.min(q, r));
numberArray[a] = min;
if(p == min) {
i++;
}
if(q == min) {
j++;
}
if(r == min) {
k++;
}
}
return numberArray[n-1];
}
/* * 笨办法 * */
public static int getChouShu(int n){
int number=0;
int findCount=0;//已找到丑数的个数
while(findCount
int i=++number;
while(i%2==0){
i/=2;
}
while(i%3==0){
i/=3;
}
while(i%5==0){
i/=5;
}
if(i==1){
findCount++;
}
}
return number;//返回第n个丑数number
}
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
System.setIn(new FileInputStream("G:\\uglynumber.txt"));
Scanner sc = new Scanner(System.in);
while(sc.hasNextLine()) {
int N=sc.nextInt();
// int ANSWER = getUglyNumber(N);
int ANSWER = getChouShu(N);
System.out.println("第 "+N+" 个 Ugly Number是: "+ ANSWER);
}
}
}
(完)