最大公约数和最小公倍数求解,常用的方法是短除法进行因式分解,然后最大公约数是所有公共因子的乘积,最小公倍数是所有因子的乘积。
本质上求最小公倍数就是求最大公倍数:x=m*a
, y=m*b
;m是最大公约数,那最小公倍数就是m*a*b
。所以可以得到最大公约数与最小公倍数的关系:
LCM(A,B) × GCD(A,B)=A × B
其中LCM是最小公倍数,GCD是最大公约数
来源:https://blog.csdn.net/Holmofy/article/details/76401074
作者总结出来的结论非常的有用,我们后续就根据这个思路去写算法。
辗转相除法(欧几里得算法)求最大公约数
辗转相除法:辗转相除法, 又名欧几里德算法(Euclidean algorithm),是求最大公约数的一种方法。它的具体做法是:用较大数除以较小数,除数去除出现的余数(第一余数),再用第一余数去除出现的余数(第二余数),如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。
来源:https://baike.baidu.com/item/辗转相除法/4625352?fr=aladdin
注:百度百科里面的描述好像不对。大家可以比较下
具体算法如下:
int max_gcd(int a,int b){
if (a <= 0 || b <= 0) {
printf("please > 0\n");
return -1;
}
if (a<b) {
int tmp = a;
a= b;
b = tmp;
}
int r;
while (a%b > 0) {
r = a%b;
a = b;
b = r;
}
return b;
}
辗转相除法的时间复杂度:我们已知斐波纳契数列增长速度是指数,那么待分析的数列也是指数增长.设欧几里得算法需要k次,那么j=O(2^k),则k=O(lg j).
结合文章开头对于公约数的概念,我这边还有另外的一种方案去实现,具体代码如下:
int max_gcd1(int a,int b){
if (a <= 0 || b <= 0) {
printf("please > 0\n");
return -1;
}
if (a<b) {
int tmp = a;
a= b;
b = tmp;
}
int max = 1;
for (int i = 1; i<=b; i++) {
if (b%i == 0 && a%i == 0) {
int tmpMax = max * i;
if (tmpMax <= b) {
if (b%tmpMax == 0 && a%tmpMax == 0){
max = tmpMax;
i = tmpMax;
}else{
max = i;
}
}else{
max = i;
}
}
}
return max;
}
大家可以清晰的感觉到无论是从运算的速度,以及逻辑的清晰度来说,辗转相除法都有非常大的优势。
在网上搜了一下,发现我国古代数学家提出了一个更相减损法的算法去求最大公约数。描述如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
根据描述,我这边实现如下:
int max_gcd2(int a,int b){
int c = 1;
while (a%2 == 0 && b%2 == 0) {
c *= 2;
a = a/2;
b = b/2;
}
while (a != b) {
if (a > b) {
a = a - b;
}else{
b = b - a;
}
}
return a * c;
}
两种算法的区别
(1)两者都是求最大公因数的方法,计算上辗转相除法以除法为主,更相减损术以减法为主,计算次数上辗转相除法计算次数相对较少,特别当两个数字大小区别较大时计算次数的区别较明显。
(2)从结果体现形式来看,辗转相除法体现结果是以相除余数为0则得到,而更相减损术则以减数与差相等而得到。
转载地址:https://blog.csdn.net/Holmofy/article/details/76401074
更多优质文章,可以微信扫码关注: