最大公因數和最小公倍數算法
這里只介紹最大公因數算法,因為最小公倍數其實就是兩數相乘再除以最大公因數
我們經常會遇到有關數論的題目,求解最大公因數便是常見的題目之一,以下為幾種常見的方法,他們的主要結構均為遞歸
(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);
}
}