问题:求两个整数的最大公约数
方法一:辗转相除法
原理:欧几里得算法
两个正整数a 和 b (a > b),他们的最大公约数等于 a 除以 b 的余数 c 和 b之间的最大公约数。
代码实现:
public static int getGreatestCommonDivisorV1(int a, int b){
int max = a > b ? a : b;
int min = a < b ? a : b;
if(max % min == 0){
return min;
}
return getGreatestCommonDivisorV1(max % min,min);
}
辗转相除法缺点:两个整数较大时,取模运算的性能会比较差,由此引出第二种方法
方法二:更相减损法
原理:
两 个 正 整 数 a 和 b( a > b), 它 们 的 最 大 公 约 数 等 于 a-b 的 差 值 c 和 较 小 数 b 的 最 大 公 约 数。
递归结束条件:a = b
代码实现:
//更相减损法
public static int getGreatestCommonDivisorV2(int a, int b){
int big = a > b ? a : b;
int small = a < b ? a : b;
if(big == small){
return small;
}
return getGreatestCommonDivisorV1(big - small ,small);
}
缺点:当两个数相差很大的时候,递归的次数就会很大,例如1000和1
最终版:结合两个算法
当 a 和 b 均 为 偶 数 时, gcd( a, b) = 2 × gcd( a/ 2, b/ 2) = 2 × gcd( a > > 1, b > > 1)。
当 a 为 偶 数, b 为 奇 数 时, gcd( a, b) = gcd( a/ 2, b) = gcd( a > > 1, b)。
当 a 为 奇 数, b 为 偶 数 时, gcd( a, b) = gcd( a, b/ 2) = gcd( a, b > > 1)。
当 a 和 b 均 为 奇 数 时, 先 利 用 更 相 减 损 术 运 算 一 次, gcd( a, b) = gcd( b, a-b), 此 时 a-b 必 然 是 偶 数, 然 后 又 可 以 继 续 进 行 移 位 运 算。
代码实现:
//结合二者
public static int getGreatestCommonDivisorV3(int a, int b) {
if (a == b) {
return a;
}
//a 为奇数, b 为偶数
if ((a & 1) != 0 && (b & 1) == 0) {
return getGreatestCommonDivisorV3(a, b >> 1);
} else if ((a & 1) == 0 && (b & 1) != 0) {//a 为偶数, b 为奇数
return getGreatestCommonDivisorV3(a >> 1, b);
} else if ((a & 1) == 0 && (b & 1) == 0) {//a 为偶数, b 为偶数
return getGreatestCommonDivisorV3(a >> 1, b >> 1)<<1;
} else {
//a 为奇数, b 为奇数
int big = a > b ? a : b;
int small = a < b ? a : b;
return getGreatestCommonDivisorV3(big - small, small);
}
}