摘要:主要用到了輾轉相除法(歐幾里得算法),更相減損術。
題目:求出兩個整數的最大公約數。
方法一:
暴力枚舉的方法,試圖尋找到一個合適的整數 i,看看這個整數能否被兩個整型參數numberA和numberB同時整除。
這個整數 i 從2開始循環累加,一直累加到 numberA 和 numberB 中較小參數的一半爲止。循環結束後,上一次尋找
到的能夠被兩數整除的最大 i 值,就是兩數的最大公約數。
方法二:
輾轉相除法, 又名歐幾里得算法(Euclidean algorithm),目的是求出兩個正整數的最大公約數。它是已知最古老
的算法, 其可追溯至公元前300年前。
這條算法基於一個定理:兩個正整數a和b(a>b),它們的最大公約數等於a除以b的餘數c和b之間的最大公約數。比
如10和25,25除以10商2餘5,那麼10和25的最大公約數,等同於10和5的最大公約數。
方法三:
更相減損術, 出自於中國古代的《九章算術》,也是一種求最大公約數的算法。
他的原理更加簡單:兩個正整數a和b(a>b),它們的最大公約數等於a-b的差值c和較小數b的最大公約數。比如10和25,25減去10的差是
15,那麼10和25的最大公約數,等同於10和15的最大公約數。
方法四:
衆所周知,移位運算的性能非常快。對於給定的正整數a和b,不難得到如下的結論。其中gcb(a,b)的意思是a,b的最大公約數函數:
當a和b均爲偶數,gcb(a,b) = 2*gcb(a/2, b/2) = 2*gcb(a>>1, b>>1)
當a爲偶數,b爲奇數,gcb(a,b) = gcb(a/2, b) = gcb(a>>1, b)
當a爲奇數,b爲偶數,gcb(a,b) = gcb(a, b/2) = gcb(a, b>>1)
當a和b均爲奇數,利用更相減損術運算一次,gcb(a,b) = gcb(b, a-b), 此時a-b必然是偶數,又可以繼續進行移位運算。
比如計算10和25的最大公約數的步驟如下:
-
整數10通過移位,可以轉換成求5和25的最大公約數
-
利用更相減損法,計算出25-5=20,轉換成求5和20的最大公約數
-
整數20通過移位,可以轉換成求5和10的最大公約數
-
整數10通過移位,可以轉換成求5和5的最大公約數
-
利用更相減損法,因爲兩數相等,所以最大公約數是5
在兩數比較小的時候,暫時看不出計算次數的優勢,當兩數越大,計算次數的節省就越明顯。
注:至於除二爲什麼不會破壞求最大公約數,需要思考下。基本的數學知識,如果不理解一奇一偶時爲什麼偶數除二還想等的話,可以這麼
理解,奇數的最大公約數中是不會出現2的。
注:java和python中!numberA&1都可以通過這種位運算判斷奇偶(python中代碼print(numberA&1))。但是這種位
運算判斷後返回的應該是0或1,需要再用==判斷一下。
(java中代碼System.out.println(!((numberA&1)==0));)
(python中代碼print(numberA&1==1))
最後總結一下上述所有解法的時間複雜度:
1.暴力枚舉法:時間複雜度是O(min(a, b))) 【注:不要認爲是O(min(a, b))/2) ...】
2.輾轉相除法:時間複雜度不太好計算,可以近似爲O(log(max(a, b))),但是取模運算性能較差。
3.更相減損術:避免了取模運算,但是算法性能不穩定,最壞時間複雜度爲O(max(a, b)))
4.更相減損術與移位結合:不但避免了取模運算,而且算法性能穩定,時間複雜度爲O(log(max(a, b)))
注:這篇文章轉載的時候其實還有很多坑沒有細數,例如這兩個算法的驗證等。