本文是對 Swift Algorithm Club 翻譯的一篇文章。
Swift Algorithm Club是 raywenderlich.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
兩個數字a
和b
的 最大公約數(或最大公因數)是將a
和b
整除都沒有餘數的最大正整數。算法
例如,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%b
是a
除以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。
兩個數字a
和b
的最小公倍數是二者的倍數中最小的正整數。 換句話說,LCM能夠被a
和b
整除。
例如: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時,發現了這個算法。