求兩個非零整數a ,b的最大公約數.本人在最初想到的是最粗暴的方式,其實就是小學老師教的分解因數git
func gcd(_ a :Int ,_ b :Int) -> Int {
if a == b {//若是兩個數相等.則直接返回
return a
}
let big = max(a, b)
let small = min(a, b)
var divi = 0
for i in 1..<small+1 {//選出兩個數中較小的那個數將其分解因數
if small % i == 0{
divi = small/i //分解因子,由於是從1到small遍歷.因此i 爲較小的那個 ,divi爲較大的那個
if big%divi == 0{//判斷divi可否被較大的那個數整除,若是能則divi是最大公約數
return divi
}
}
}
return 1
}
複製代碼
這個算法邏輯比較簡單,可是還不夠快,接下來看一下優質解法,歐幾里得算法. 能夠參考swift-algorithm-club中對最大公約數的解法.github
歐幾里得算法公式爲:
gcd(a, b) = gcd(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
}
}
複製代碼
這樣寫的好處不只比以前的代碼簡潔的多,並且最大的好處是當數字特別大的時候比分解因子要快不少. 舉個例子// 求 7623 和 10989公約數.若是是使用用歐幾里得算法來計算的話swift
1. gcd(10989 ,7623) = gcd(7623 ,10989 % 7623) =
2. gcd(7623,3366) = gcd(3366 , 7623 % 3366) =
3. gcd(3366 ,891) = gcd(891 ,3366 % 891) =
4. gcd(891 ,693) = gcd(693 ,891 % 693) =
5. gcd(693 , 198) = gcd(198 , 693 % 198) =
6. gcd(198 ,99) = gcd (99 , 198 % 99) =
7. gcd(99 , 0)
複製代碼
只須要7次計算就能等到最大公約數,若是用上面分解數字的辦法 須要for循環循環到 (7623/99 = 77)時才能獲得7623和10989的最大公因數.bash
可是gcd(a ,b) = gcd(b ,a % b)是怎麼來的,勾起了對證實歐幾里得算法的渴望.如下是證實過程ui
令c = gcd(a,b),則設 a = mc , b = nc .spa
令 a = kb + r (a > b ,a,b,k,r皆爲正整數,且r<b) ,r爲a除以b的餘數 r = a - kb = mc -knc = c(m-kn)code
條件1中的 b = nc ,條件2中的 r = (m-kn)c,則b和r有公約數c,只要證實 (m -kn)與n互質,就能證實c是b與r的最大公約數.get
用反證法證實m-kn 與 n互質,假設 m-kn 與 n 不互質既有除1以外的公約數it
則可設m- kn = xd , n = yd (d > 1)
m - kyd = xd , m = kyd + xd ,a = mc 則 a = kydc + xdc = (ky + x)dc, b = ydc
那麼a,b的最大公約數則是dc 不是c ,與c = gcd(a,b)的設定衝突,因此(m-kn)與n互素,因此r,與b最大的公約數也是c.因此 gcd(a,b) = gcd(b,a % b)
證實完畢.若有邏輯錯誤或者是表述不清楚,看不懂的地方但願你們能指出.(好久沒有寫文章了.本身都感受很亂)