本系列文章将于2021年整理出版。前驱教材:《算法竞赛入门到进阶》 清华大学出版社
网购:京东 当当 做者签名书:点我
公众号同步:算法专辑
暑假福利:胡说三国
有建议请加QQ 群:567554289html
最大公约数java
1. GCD定义
整数a和b的最大公因数是指能同时整除a和b的最大整数,记为gcd(a, b)。
例如:gcd(15, 81) = 3,gcd(0, 44) = 44,gcd(0, 0) = 0,gcd(-6, -15) = 3,gcd(-17,289) = 17。
注意:因为-a的因子和a的因子相同,所以gcd(a, b) = gcd(|a|, |b|)。编码时只须要关注正整数的最大公因数。c++
2. GCD性质
(1)gcd(a,b) = gcd(a, a+b) = gcd(a, ka+b)
(2)gcd(ka, kb) = k·gcd(a, b)
(3)定义多个整数的最大公约数:gcd(a, b, c) = gcd(gcd(a, b), c)
(4)若gcd(a, b) = d,则gcd(a/d, b/d) = 1,即a/d与b/d互素。这个定理很重要。
(5)gcd(a+cb, b) = gcd(a, b)web
3. GCD编码
编程时能够直接用c++函数std::__gcd(a, b)。注意:参数a和b都应该是正整数,不然可能会返回负数。下面介绍三种算法。算法
3.1 欧几里得算法
用展转相除法求gcd,即gcd(a, b) = gcd(b, a mod b)。代码是:编程
int gcd(int a, int b){ // 通常要求a>=0, b>0。若a=b=0,代码也正确,返回0
return b? gcd(b, a%b):a;
}
这是竞赛中最经常使用的编码,它极为高效,“拉梅定理”给出了复杂度分析。
拉梅定理:用欧几里得算法计算两个正整数的最大公因数,须要的除法次数不会超过两个整数中较小的哪一个十进制数的位数的5倍。
推论:用欧几里得算法求gcd(a, b),a > b,须要O
(
(
l
o
g
2
a
)
3
)
O((log_2a)^3)O((log2a)3)次位运算。
欧几里得算法的缺点是须要作除法取模运算,而高精度大数的除法比较耗时,此时能够用“更相减损术”app
不过,在竞赛中不太可能直接使用“更相减损术”和stein算法求最大公约数。下面的介绍,只是为了帮助读者理解GCD的性质。ide
3.2 更相减损术
计算基于这一性质:gcd(a, b) = gcd(b, a-b) = gcd(a, a-b)。svg
计算步骤:用较大的数减较小的数,把所得的差与较小的数比较,而后继续作减法操做,直到减数和差相等为止。
编码也很简单:函数
int gcd(int a, int b){
while(a != b){ //a==b时结束计算
if(a > b) a = a - b;
else b = b - a;
}
return a;
}
更相减损术虽然避免了欧几里得的取模计算,可是计算次数比欧几里得算法多不少,极端状况下须要计算O
(
m
a
x
(
a
,
b
)
)
O(max(a, b))O(max(a,b))次,例如a = 100,b = 1时,需计算100次。