漫畫算法:展轉相除法是什麼鬼?

​大四畢業前夕,計算機學院的小灰又一次頂着炎炎烈日,程序員

去某IT公司面試研發工程師崗位......面試






半小時後,公司會議室,面試開始......算法




















小灰奮筆疾書,五分鐘後......ide






小灰的思路十分簡單。他使用暴力枚舉的方法,試圖尋找到一個合適的整數 i,看看這個整數可否被兩個整型參數numberA和numberB同時整除。函數


這個整數 i 從2開始循環累加,一直累加到numberA和numberB中較小參數的一半爲止。循環結束後,上一次尋找到的可以被兩數整除的最大 i 值,就是兩數的最大公約數。性能



















過後,垂頭喪氣的小灰去請教同系的學霸大黃......優化











展轉相除法, 又名歐幾里得算法(Euclidean algorithm),目的是求出兩個正整數的最大公約數。它是已知最古老的算法, 其可追溯至公元前300年前。idea


這條算法基於一個定理:兩個正整數a和b(a>b),它們的最大公約數等於a除以b的餘數c和b之間的最大公約數。好比10和25,25除以10商2餘5,那麼10和25的最大公約數,等同於10和5的最大公約數。3d





有了這條定理,求出最大公約數就簡單了。咱們可使用遞歸的方法來把問題逐步簡化。cdn


首先,咱們先計算出a除以b的餘數c,把問題轉化成求出b和c的最大公約數;而後計算出b除以c的餘數d,把問題轉化成求出c和d的最大公約數;再而後計算出c除以d的餘數e,把問題轉化成求出d和e的最大公約數......


以此類推,逐漸把兩個較大整數之間的運算簡化成兩個較小整數之間的運算,直到兩個數能夠整除,或者其中一個數減少到1爲止。




五分鐘後,小灰改好了代碼......













更相減損術, 出自於中國古代的《九章算術》,也是一種求最大公約數的算法。


他的原理更加簡單:兩個正整數a和b(a>b),它們的最大公約數等於a-b的差值c和較小數b的最大公約數好比10和25,25減去10的差是15,那麼10和25的最大公約數,等同於10和15的最大公約數。




由此,咱們一樣能夠經過遞歸來簡化問題。首先,咱們先計算出a和b的差值c(假設a>b),把問題轉化成求出b和c的最大公約數;而後計算出c和b的差值d(假設c>b),把問題轉化成求出b和d的最大公約數;再而後計算出b和d的差值e(假設b>d),把問題轉化成求出d和e的最大公約數......


以此類推,逐漸把兩個較大整數之間的運算簡化成兩個較小整數之間的運算,直到兩個數能夠相等爲止,最大公約數就是最終相等的兩個數。








五分鐘後,小灰重寫了代碼......













衆所周知,移位運算的性能很是快。對於給定的正整數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的最大公約數的步驟以下:


  1. 整數10經過移位,能夠轉換成求5和25的最大公約數

  2. 利用更相減損法,計算出25-5=20,轉換成求5和20的最大公約數

  3. 整數20經過移位,能夠轉換成求5和10的最大公約數

  4. 整數10經過移位,能夠轉換成求5和5的最大公約數

  5. 利用更相減損法,由於兩數相等,因此最大公約數是5


在兩數比較小的時候,暫時看不出計算次數的優點,當兩數越大,計算次數的節省就越明顯。









最後總結一下上述全部解法的時間複雜度:

1.暴力枚舉法:時間複雜度是O(min(a, b)))

2.展轉相除法:時間複雜度不太好計算,能夠近似爲O(log(max(a, b))),可是取模運算性能較差。

3.更相減損術:避免了取模運算,可是算法性能不穩定,最壞時間複雜度爲O(max(a, b)))

4.更相減損術與移位結合:不但避免了取模運算,並且算法性能穩定,時間複雜度爲O(log(max(a, b)))






本文本來只寫到展轉相除法就終告結束,後來網友們指出還有更優化的解法,看來本身仍是才疏學淺,很感謝你們指出問題。另外,方法的參數默認一定是正整數,因此在代碼中省去了合法性檢查。


文中描述的更相減損術是簡化了的方式。在九章算術原文中多了一步驗證:若是兩數都是偶數,計算差值以前會首先讓兩個數都折半,使得計算次數更少。這種方法作到了部分優化,但古人彷佛沒想到一奇一偶的狀況也是能夠優化的。


因爲篇幅所限,本文省略了關於展轉相除法原和更相減損術的原理及證實。其實證實過程並不複雜,細心的同窗們也能夠本身嘗試研究一下。謝謝你們的捧場!




—————END—————




喜歡本文的朋友們,歡迎長按下圖關注訂閱號程序員小灰,收看更多精彩內容

相關文章
相關標籤/搜索