【譯】Swift算法俱樂部-最大公約數算法

本文是對 Swift Algorithm Club 翻譯的一篇文章。
Swift Algorithm Clubraywenderlich.com網站出品的用Swift實現算法和數據結構的開源項目,目前在GitHub上有18000+⭐️,我初略統計了一下,大概有一百左右個的算法和數據結構,基本上常見的都包含了,是iOSer學習算法和數據結構不錯的資源。
🐙andyRon/swift-algorithm-club-cn是我對Swift Algorithm Club,邊學習邊翻譯的項目。因爲能力有限,如發現錯誤或翻譯不妥,請指正,歡迎pull request。也歡迎有興趣、有時間的小夥伴一塊兒參與翻譯和學習🤓。固然也歡迎加⭐️,🤩🤩🤩🤨🤪。
本文的翻譯原文和代碼能夠查看🐙swift-algorithm-club-cn/Greatest Common Divisorgit


最大公約數算法(Greatest Common Divisor)github

兩個數字ab最大公約數(或最大公因數)是將ab整除都沒有餘數的最大正整數。算法

例如,gcd(39, 52) = 13,由於13除以39(39/13 = 3)以及52(52/13 = 4),並且沒有比13更大的數字。swift

在某些時候你可能不得不在學校裏瞭解這一點。:-)安全

找到兩個數字的GCD的費力方法是先找出兩個數字的因子,而後取其共同的最大數。 問題在於分解數字是很是困難的,特別是當它們變大時。 (從好的方面來講,這種困難也是保證您的在線支付安全的緣由。)數據結構

有一種更聰明的方法來計算GCD:歐幾里德的算法。 這個算法主要觀點是,dom

gcd(a, b) = gcd(b, a % b)
複製代碼

其中a%ba除以b的餘數。函數

如下是Swift中這個想法的實現:學習

func gcd(_ a: Int, _ b: Int) -> Int {
  let r = a % b
  if r != 0 {
    return gcd(b, r)
  } else {
    return b
  }
}
複製代碼

在 playground 上,試試一些例子:測試

gcd(52, 39)        // 13
gcd(228, 36)       // 12
gcd(51357, 3819)   // 57
複製代碼

讓咱們分步完成第三個例子:

gcd(51357, 3819)
複製代碼

根據歐幾里德的規則,這至關於,

gcd(3819, 51357 % 3819) = gcd(3819, 1710)
複製代碼

由於51357 % 3819的餘數是1710。 詳細計算爲51357 = (13 * 3819) + 1710,但咱們只關心餘數部分。

因此gcd(51357, 3819)gcd(3819, 1710)相同。 這頗有用,由於咱們能夠繼續簡化:

gcd(3819, 1710) = gcd(1710, 3819 % 1710) = 
gcd(1710, 399)  = gcd(399, 1710 % 399)   = 
gcd(399, 114)   = gcd(114, 399 % 114)    = 
gcd(114, 57)    = gcd(57, 114 % 57)      = 
gcd(57, 0)
複製代碼

如今不能再進一步劃分了。 114 / 57的餘數爲零,由於114 = 57 * 2。 這意味着咱們找到了答案:

gcd(3819, 51357) = gcd(57, 0) = 57
複製代碼

所以,在歐幾里德算法的每一個步驟中,數字變得更小,而且在某個點上,當它們中的一個變爲零時它結束。

順便說一下,兩個數字的GCD也可能爲1.它們被認爲是 互素(譯註:也叫互質)。 當沒有數字將它們整除時會發生這種狀況,例如:

gcd(841, 299)     // 1
複製代碼

下面是歐幾里德算法略微不一樣的一種實現。 與第一個版本不一樣,它不使用遞歸,而只使用基本的while循環。

func gcd(_ m: Int, _ n: Int) -> Int {
  var a = 0
  var b = max(m, n)
  var r = min(m, n)

  while r != 0 {
    a = b
    b = r
    r = a % b
  }
  return b
}
複製代碼

函數頂部的 max()min() 確保咱們老是用較大的數字除以較小的數字。

最小公倍數

與GCD相關的想法是 最小公倍數 或叫作LCM。

兩個數字ab的最小公倍數是二者的倍數中最小的正整數。 換句話說,LCM能夠被ab整除。

例如:lcm(2, 3) = 6,由於6能夠被2整除,也能夠被3整除。

咱們也可使用歐幾里德算法計算LCM:

a * b
lcm(a, b) = ---------
            gcd(a, b)
複製代碼

代碼:

func lcm(_ m: Int, _ n: Int) -> Int {
  return m / gcd(m, n) * n
}
複製代碼

在playground中測試:

lcm(10, 8)    // 40
複製代碼

您可能不須要在任何實際問題中使用GCD或LCM,可是使用這種古老的算法很酷。 它首先由歐幾里德在公元前300年左右他的書籍元素中描述。 有傳言說他在攻擊他的Commodore 64時,發現了這個算法。

做者:Matthijs Hollemans
翻譯:Andy Ron
校對:Andy Ron

相關文章
相關標籤/搜索