java算一个数的所有因子。
最简单粗暴的方法:从1遍历到num,如果能被num整除,就是num的因子。
//该方法传入两个参数。一个是num(求num的因子);一个是arr数组,用来存放num的因子
public static void fun1(int num,ArrayList<Integer> arr){
for ( int i = 1 ; i <= num ; i++ ){
if ( num % i == 0 ){
arr.add(i); //将因子存放到arr数组中
}
}
}
显而易见,当num的值较小的时候,该方法非常简单。但是,如果num非常的大,那么,这个算法的时间是非常久的。
我们来测试一下,当num的值为999999999(9位数)时,程序用时大概1650毫秒。已经大于1秒钟,产生肉眼可见的延迟。
int num = 999999999;
ArrayList<Integer> arr = new ArrayList<>();
long startTime = System.currentTimeMillis(); //开始
fun1(num,arr);
long endTime = System.currentTimeMillis(); //结束
System.out.println(endTime - startTime);
所以刚刚的算法肯定是不行的。那么优化后的算法如下:
public static void fun(int num,ArrayList<Integer> arr){
//从1遍历到num的平方跟即可。
//这时你可能会说,那后面的数呢,比如num本身,不是计算不到了嘛?
//别急,看for循环里面的处理情况
for ( int i = 1 ; i <= Math.sqrt(num) ; i++ ){
//如果能被num整除,那肯定是num的因子,毫无疑问
if ( num % i == 0 ){
arr.add(i);
//重点的部分在这里!!!
//当i能被num整除的情况下,此时i是相对较小的因子,用i求出num另一个较大的因子n
//因为当i能被num整除时,那么数"num/i"也一定能被num整除
//不需要再进行重复的计算,这样算法的运行时间大大降低
int n = num / i;
//但用i算出另一个较大的因子时,会出现重复的情况
//例如num = 4,当遍历到2时,算出另一个较大的因子也是2,这就重复了,要判断一下
if ( n != i ){
arr.add(n);
}
}
}
}
我们再来试试这个算法的运行时间。差不多1毫秒,明显比上一个算法快非常多。
int num = 999999999;
ArrayList<Integer> arr = new ArrayList<>();
long startTime = System.currentTimeMillis (); //开始
fun(num,arr);
long endTime = System.currentTimeMillis (); //结束
System.out.println(endTime - startTime);
我们再来看看两个算法得到的因子是否相同:
写一个方法用于输出数组。
public static void printf(ArrayList<Integer> arr){
Collections.sort(arr); //给因子从小到大排序,方便查阅
for ( int i = 0 ; i < arr.size() ; i++ ){
System.out.print(arr.get(i)+" ");
}
System.out.println("");
}
主程序:
定义两个数组,数组arr存放优化算法得到的因子,数组arr1存放旧算法得到的数组。
int num = 999999999;
ArrayList<Integer> arr = new ArrayList<>();
ArrayList<Integer> arr1 = new ArrayList<>();
fun(num,arr);
printf(arr);
fun1(num,arr1);
printf(arr1);
输出结果:
1 3 9 27 37 81 111 333 999 2997 333667 1001001 3003003 9009009 12345679 27027027 37037037 111111111 333333333 999999999
1 3 9 27 37 81 111 333 999 2997 333667 1001001 3003003 9009009 12345679 27027027 37037037 111111111 333333333 999999999
可以看到一模一样,所以说优化过后的算法是非常好的。而且,我在运行程序时,第一个数组arr(优化算法)的输出非常的快,肉眼无法捕捉。而第二个数组(旧算法)的输出延迟特别明显。