求两个非零整数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)
证实完毕.若有逻辑错误或者是表述不清楚,看不懂的地方但愿你们能指出.(好久没有写文章了.本身都感受很乱)