求最大公约数的若干个方法:
暴力枚举
辗转相除法(欧几里得算法)
更相减损法(九章算术)
- 上两种方法的结合
优化版本
public class GCD {
/**
* 2 * x == k, 或者 2 * x + 1 == k
* 既然要求最大公约数,我们就从最大的数开始,
* 那么就如上面所示,最先从x开始考虑
* @param a
* @param b
* @return
*/
public static int gcd(int a, int b) {
int big = Math.max(a, b);
int small = Math.min(a, b);
if(big % small == 0) {
return small;
}
for(int i = small >> 1 ; i > 1 ; i--) {
if(small % i == 0 && big % i == 0) {
return i;
}
}
return 1;
}
/**
* 辗转相除法(欧几里得算法)
*
* 如果算法入口处 a < b,例如 5, 25
* 则这个算法会自动将5,25进行交换
* gcd1(5, 25) = gcd1(25, 5 % 25) = gcd1(25, 5)
*
* 而总是有b > a % b,所以这个算法总能够保证 a >= b
* @param a
* @param b
* @return
*/
public static int gcd1(int a, int b) {
return b == 0 ? a : gcd1(b, a % b);
}
/**
* 更相减损法
* @param a
* @param b
* @return
*/
public static int gcd2(int a, int b) {
if(a == b) {
return a;
}
int big = Math.max(a, b);
int small = Math.min(a, b);
return gcd2(big-small, small);
}
/**
* a, b均为偶数, 则 gcd(a, b) = 2 * gcd(a/2, b/2) = gcd(a >> 1, b >> 1) << 1;
* a为奇数,b为偶数,则 gcd(a, b) = gcd(a, b >> 1)
* a为偶数,b为奇数 则 gcd(a, b) = gcd(a >> 1, b)
* a,b均为奇数, 则 gcd(a, b) = gcd(a - b, b) {假设a >= b}
* @param a
* @param b
* @return
*/
public static int gcd3(int a, int b) {
if(a == b) {
return a;
}
if((a & 1) == 0 && (b & 1) == 0) {
return gcd3(a >> 1, b >> 1) << 1;
} else if((a & 1) == 0 && (b & 1) != 0) {
return gcd3(a >> 1, b);
} else if((a & 1) != 0 && (b & 1) == 0) {
return gcd3(a, b >> 1);
} else {
int big = Math.max(a, b);
int small = Math.min(a, b);
return gcd3(big-small, small);
}
}
public static void main(String[] args) {
System.out.print(gcd(25, 5) + " ");
System.out.print(gcd(100, 80) + " ");
System.out.println(gcd(27, 14));
//
System.out.print(gcd1(25, 5) + " ");
System.out.print(gcd1(100, 80) + " ");
System.out.println(gcd1(27, 14));
//
System.out.print(gcd2(25, 5) + " ");
System.out.print(gcd2(100, 80) + " ");
System.out.println(gcd2(27, 14));
//
System.out.print(gcd3(25, 5) + " ");
System.out.print(gcd3(100, 80) + " ");
System.out.println(gcd3(27, 14));
}
}