簡述
給你兩個數a和b,要求求出a和b的最大公約數。為了解決這個問題,我們可以想到很多方法,窮舉法,輾轉相除法,更相減損法等。這里我們詳解介紹窮舉法和輾轉相除法。
問題描述
我們把問題用數學語言進行描述:已知整數a和b,求一數k滿足a%k==0&&b%k==0,且k要盡可能大。
窮舉法
因為k小於等於a和b,所以我們可以從a和b選一個數開始進行窮舉,這里我們選擇較小的那個數,因為k一定小於等於較小那個數。
int gcd(int a,int b){ int num=min(a,b); for(int i=num;i>=1;i--){ if(a%i==0&&b%i==0) return i; } }
這個算法的時間復雜度為O(min(a,b)),因為最多會執行min(a,b)次,當a和b特別大的時候,這個程序是很慢的。
輾轉相除法
輾轉相除法又稱歐幾里得算法,這是我們小學就學過的算法,古希臘數學家歐幾里德在其著作《The Elements》中最早描述了這種算法,所以被命名為歐幾里德算法,又在九章算術里描述為輾轉相除法。
我們現在將求a和b兩個數的最大公約數定義為函數gcd(a,b)。
輾轉相除法的算法思想是,gcd(a,b)=gcd(b,a%b),當b為0時gcd(a,b)為a。不斷重復gcd(a,b)=gcd(b,a%b)則b終會等於0,最后求出等式的結果。
例如我們現在要求gcd(9,12),則可以寫出以下的過程:
gcd(9,12)=gcd(12,9%12)=gcd(12,9)=gcd(9,12%9)=gcd(9,3)=gcd(3,9%3)=gcd(3,0)=3
int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b); }
輾轉相除法的時間復雜度為O(logn),證明省略。
輾轉相除法的證明
為什么gcd(a,b)=gcd(b,a%b)呢?
我們設gcd(a,b)=k,r=a%b。
可得a=sk,b=tk,s和t互質,a=bq+r,q為正整數。
左帶入右得sk=tkq+r,整理得r=k(s,tq),所以k也是r的因子。
我們可以將求gcd(a,b)的過程理解為求a和b兩個因數集合里最大的相同數,將gcd(a,b)=gcd(b,a%b)過程可以理解為使用一個r代替b,使得b變小但r的因數集里包含最大公約數k,一直減小到0時,當時的a就是我們求的k了。
我們開看一張gif圖,兩條線段的長度分別代表a和b,里面的一小段代表最大公約數,現在演示如何用輾轉相除法求最大公約數。