思路一算法
從1到兩個數中最小的數遍歷,找到能同時被兩個數都整除的數,並記錄最大的值。編程
最簡單且效率最低。code
思路二遞歸
碾轉相除法,古希臘的一位數學家歐幾里得給出的一個高效的算法。他證實了f(x,y)=f(y,x%y)數學
int gcd(int num1,int num2) { return !num2?num1:gcd(num2,num1%num2); }
很簡單的遞歸,再也不討論class
思路三效率
從思路二的算法能夠知道,用到了取模運算,也就是用到了除。若是求兩個大數的最大公約數,將是一個很昂貴的開銷,下面介紹第三種思路。書籍
若是一個數能同時被num1,num2整除,那麼確定能被num1-num2,num2整除,相反,若是一個數能同時被num1-num2,num2整除,那麼確定能同時被num1,num2整除,因此f(num1,num2)=f(num1-num2,num2),這樣就避免了取膜運算。循環
int gcd(int num1,int num2) { //遞歸終止條件,即當num2爲0,num1爲最大公約數 if(num2==0) return num1; //若是num1<num2,須要調換位置,不然會出現負數 if(num1<num2) return gcd(num2,num1); else return gcd(num1-num2,num2); }
該算法有個缺點,即當兩個相差很大的時候,例如f(10000000000,1),循環次數將大大增長。遍歷
思路四
該方法結合思路二和思路三的優勢來進行求解。
若是num1,num2都爲偶數,f(num1,num2)=2f(num1/2,num2/2)
若是num1爲奇數,num2爲偶數 f(num1,num2)=f(num1,num2/2)
若是num1爲偶數,num2爲奇數 f(num1,num2)=f(num1/2,num2)
若是num1爲奇數,num2爲奇數 f(num1,num2)=f(num1-num2,num2)
又由於除2能夠用>>1來表示,移位操做符的效率是很高的
int gcd(int num1,int num2) { if(num2==0) return num1; if(num1<num2) return gcd(num2,num1); if(!num1&0x01) { if(!num2&0x01) return 2*gcd(num1>>1,num2>>1); else return gcd(num1>>1,num2); } else { if(!num2&0x01) return gcd(num1,num2>>1); else return gcd(num1-num2,num2); } }
參考書籍:《編程之美》