求两个整数的最大公约数,要尽量优化算法的性能
思路:
方法一: 辗转相除法, 两个正整数a,b(a>b), 它们的最大公约数 = a除以b的余数c和较小数b之间的最大公约数。
例如:10和25, 25除以10=2...5, 那么10和25的最大公约数, 等同于10和余数5的最大公约数。
方法二:更相减损术, 两个正整数a,b(a>b), 它们的最大公约数 = a-b的差值c和较小数b之间的最大公约数。
例如:10和25, 25-10=15, 那么10和25的最大公约数, 等同于10和15的最大公约数。
两个整数较大时候的场景,取模性能会比较差,更相减损术更适合。但如果两个数相差悬殊,比如10000和1时,更相减损术就要递归9999次。此时可以用方法三
方法三: 更相减损术+移位(最优):
- 当a,b均为偶数时,gcd(a,b) = 2*gcd(a/2,b/2) = 2*gcd(a>>1,b>>1),gcd为方法名;
- 当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必然是偶数,然后又可以继续进行移位运算
ps. >>相当于除以2,<<相当于乘以2
代码实现:
/** * 求两个整数的最大公约数,要尽量优化算法的性能 * * 方法一:辗转相除法, 两个正整数a,b(a>b), 它们的最大公约数 = a除以b的余数c和较小数b之间的最大公约数。 * 例如:10和25, 25除以10=2...5, 那么10和25的最大公约数, 等同于10和余数5的最大公约数。 * 方法二:更相减损术, 两个正整数a,b(a>b), 它们的最大公约数 = a-b的差值c和较小数b之间的最大公约数。 * 例如:10和25, 25-10=15, 那么10和25的最大公约数, 等同于10和15的最大公约数 * 方法三: 更相减损术+移位 */ public class GreatestCommonDivisor { /** * 辗转相除法 * @param a * @param b * @return */ public static int getGreatestCommonDivisor(int a, int b){ int min = a; int max = b; if ( a >= b ){ min = b; max = a; } if (min == 0){ return max; } int p = max % min; return getGreatestCommonDivisor(min,p); } /** * 更相减损术 * @param a * @param b * @return */ public static int getGreatestCommonDivisor2(int a, int b){ int min = a; int max = b; if ( a >= b ){ min = b; max = a; } if (min == 0){ return max; } int p = max - min; return getGreatestCommonDivisor2(min,p); } /** * 更相减损术+移位(最优) * @param a * @param b * @return */ public static int getGreatestCommonDivisor3(int a, int b){ if(a == b){ return a; } if ((a&1)==0 && (b&1)==0){ return getGreatestCommonDivisor3(a>>1,b>>1)<<1; } if((a&1)==0 && (b&1)!=0){ return getGreatestCommonDivisor3(a>>1,b); } if((a&1)!=0 && (b&1)==0){ return getGreatestCommonDivisor3(a,b>>1); } if((a&1)!=0 && (b&1)!=0){ int min = a > b ? b : a; int max = a > b ? a : b; return getGreatestCommonDivisor3(min,max-min); } return 0; } public static void main (String[] args){ System.out.println("(1) The Greatest Common Divisor is: " + getGreatestCommonDivisor(24,8)); System.out.println("(2) The Greatest Common Divisor is: " + getGreatestCommonDivisor2(24,8)); System.out.println("(3) The Greatest Common Divisor is: " + getGreatestCommonDivisor3(24,8)); } }
结果:
(1) The Greatest Common Divisor is: 8 (2) The Greatest Common Divisor is: 8
(3) The Greatest Common Divisor is: 8