最大公因数和最小公倍数算法
这里只介绍最大公因数算法,因为最小公倍数其实就是两数相乘再除以最大公因数
我们经常会遇到有关数论的题目,求解最大公因数便是常见的题目之一,以下为几种常见的方法,他们的主要结构均为递归
(1)辗转相除法
(个人比较喜欢这个算法,比较简洁)
这便是著名的欧几里得算法
Euclid 规则:如果 x 和 y 是正整数,且有 x>=y,那么 gcd(x,y)=gcd(x mod y,y)。
int gcd(int a,int b)
{
if(a<b)
{
swap(a,b);
}
if(b==0)
{
return a;
}
return gcd(b,a%b);
}
例如:求 25 和 11 两个数的最大公约数,即求 gcd(25,11)
a = x * b + y --> b = x’ * (a%b) + y’ 当 y‘==0 时,a%b 即为它俩的最大公约数
25 = 2 * 11 + 3
11 = 3 * 3 + 2
3 = 1 * 2 + 1
2 = 2 * 1 + 0
(2)更相减损法
百度百科中的介绍如下:
更相减损法, 又称 "等值算法"
“关于约分问题, 实质是如何求分子, 分母最大公约数的问题.《九章算术》中介绍了这个方法, 叫做” 更相减损术”, 即 “可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用 2 约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个 2 与第二步中等数的乘积就是所求的最大公约数。
非递归实现
int gcd2(int a,int b)
{
int ans=1;
while(a%2!=0&&b%2!=0)
{
a = a/2;
b = b/2;
ans=ans*2;
}
while(a != b)
{
if(a>b)
{
a = a-b;
}else
{
b = b-a;
}
}
return ans*a;
}
递归实现
int gcd2_2(int a,int b)
{
if(a<b)
{
swap(a,b);
}
if(a==b)
{
return a;
}
int temp=a-b;
if(temp<b)
{
return gcd2_2(b,temp);
}
else
{
return gcd2_2(temp,b);
}
}
递归实现实现需在 a,b 为奇数时实现
当 a,b 为任意正整数时,可用如下方式结合然后加以实现:
int gcd2(int a,int b)
{
int ans=1;
while(a%2!=0&&b%2!=0)
{
a = a/2;
b = b/2;
ans=ans*2;
}
a=gcd2_2(a,b);
return ans*a;
}
例如:求 91 和 49 的最大公约数 gcd2(91,49)
91 - 49 = 42
49 - 42 = 7
42 - 7 = 35
35 - 7 = 28
28 - 7 = 14
14 - 7 = 7
(3)分治法
算法思想:
当 a,b 都是偶数时,gcd(a,b)=2*gcd(a/2,b/2);
当 a 是奇数,b 是偶数时,gcd(a,b)=gcd(a,b/2);
当 a 是偶数,b 是奇数时,gcd(a,b)=gcd(a/2,b);
当 a,b 都是奇数时,gcd(a,b)=gcd((a-b)/2,b).
代码实现如下:
int gcd3(int a,int b)
{
if(a<b)
{
swap(a,b);
}
if(b==0)
{
return a;
}
if(a%2==0&&b%2==0)
{
return 2*gcd3(a/2,b/2);
}
else if(a%2!=0&&b%2==0)
{
return gcd3(a,b/2);
}
else if(a%2==0&&b%2!=0)
{
return gcd3(a/2,b);
}
else if(a%2!=0&&b%2!=0)
{
return gcd3((a-b)/2,b);
}
}