最大公约数
问题概述:
求两数的最大公约数,要求时间复杂度尽可能小
问题本质:
经典算法使用、灵活位运算
思路:
- 利用辗转相除法
- 利用更相减损术
- 针对两个方法缺点进行改进融合
- 使用位运算提高计算机处理性能
package algorithm;
/**
* 最大公约数算法
* 1、辗转相除法
* 2、更相减损术
* 3、二者结合
*/
public class CommonDivisor {
public static void main(String[] args) {
//辗转相除法
System.out.println(GreatestCommonDivisor1(9, 3));
//更相减损术
System.out.println(GreatestCommonDivisor2(7, 3));
//两者结合
System.out.println(GreatestCommonDivisor3(9, 3));
}
/**
* 辗转相除法,a/b = x ... d 公约数为b/d=x1...d1 递归执行直到余数为0(最差情况下除数为1)
* 缺点:%运算大数情况下效率较低
*/
public static int GreatestCommonDivisor1(int a,int b){
int d = a%b;
if(d==0){
return b;
}
return GreatestCommonDivisor1(b,d);
}
/**
* 更相减损术:a-b=c 取b与c中最大值继续big-small直到差为0(即big==small)
* 优点:避免了%运算
* 缺点:当两数差距较大时运算次数过多
*/
public static int GreatestCommonDivisor2(int a,int b){
if(a==b){
return b;
}
int big = a>b?a:b;
int small = a<b?a:b;
return GreatestCommonDivisor2(big-small,small);
}
/**
* 两者结合
* 分析两个数的奇偶性
* 当a b均为偶数时,将a b提取公因式2之后求两数的最大公约数
* 当a为偶数b为奇数时,将a除以2,求a/2与b的最大公约数
* 当a为奇数b为偶数时,将b除以2,求a与b/2的最大公约数
* 当a b均为奇数时,进行一次更相减损术,a-b=c,c一定为偶数
* 总结:如果数为偶数可以除以2缩小两个数的差距,减少运算次数以提高效率
*/
public static int GreatestCommonDivisor3(int a,int b){
if(a==b){
return b;
}
if((a&1)==0 && (b&1)==0){
return GreatestCommonDivisor3(a>>1,b>>1)<<1;
}else if((a&1)==0 && (b&1)!=0){
return GreatestCommonDivisor3(a>>1,b);
}else if((a&1)!=0 && (b&1)==0){
return GreatestCommonDivisor3(a,b>>1);
}else{
int big = a>b?a:b;
int small = a<b?a:b;
return GreatestCommonDivisor3(big-small,small);
}
}
}