題目:求兩個數的最大公約數,要儘量優化算法的性能
- 方法一:暴力枚舉是絕對不可取的,效率不高如果我們傳入的整數是10000和10001,那我們需要循環10000 / 2 - 1 = 4999
for(int i = small / 2; i > 1; i--) {
if(small % i == 0 && big % i == 0) {
return i;
}
}
return 1;
- 方法二:輾轉相除法。
輾轉相除,又叫歐幾里得算法,該算法的目的求兩個數的最大公約數。他是已知最古老的算法,要追溯到公園300年前。
原理:兩個正整數a 和 b (a > b),他們的最大公約數等於a 除以b的餘數c 和 b之間的最大公約數。
代碼實現:
///Swift 實現
func getGreateCommonDivisor(_ number: Int, _ number2: Int) -> Int {
let big = number > number2 ? number : number2
let small = number2 > number ? number : number2
if big % small == 0 {
return small
}else {
return getGreateCommonDivisor(big % small, small)
}
}
缺點:當兩個數都比較大的時候,取模運算的性能比較差
- 方法三:更相減損術
更相減損術:出自中國古代《九章算術》,也是一種求最大公約數的算法。
原理:兩個正整數a > b ,他們的最大公約數等於a - b的差值c 和 較小數b的最大公約數,直到,兩個數相等,就是他們的最大公約數啦
例如:15 和 10,第一次相減 5 和 10, 第二次:5 和 5啦,那他們的最大公約數就是5.
代碼:
///遞歸調用
func getGreateCommonDivisorV3(_ number: Int, _ number2: Int) -> Int {
let big = number > number2 ? number : number2
let small = number2 > number ? number : number2
if big == small {
return small
}else {
return getGreateCommonDivisor(big - small, small)
}
}
缺點:當兩個數相差很大的時候,那麼相減次數就會很多,該算法是不穩定算法,例如:10000 和 3 就要遞歸大約: 10000 / 3次
- 方法四: 移位運算和更相減損術結合,達到比較好的效果
解釋:衆所周知,位運算的性能非常好。
說明:公約數用gcd() 表示,其中a > b
當a和b都是偶數時:gcd(a, b) = 2 x gcd(a / 2, b / 2) = 2 x gcd(a>>1, b>>1)
當a爲偶數和b爲奇數時,gcd(a, b) = gcd(a / 2, b ) = gcd(a>>1, b)
當b爲偶數和a爲奇數時,gcd(a, b) = gcd(a , b / 2 ) = gcd(b>>1, a)
當a和b都是奇數時,先利用更相減損術運算一次,gcd(a, b) = gcd(b, a - b),此時a - b必然是偶數,然後可以繼續利用移位運算。
這種算法的優勢,當兩個數越大時,計算次數的減少就越明顯。
例如:15 和 25的最大公約數
第一次:都爲奇數,兩者相減:10 , 15
第二次:10是偶數,變爲:5 , 15
第三次:都是奇數,兩者相減:5, 10
第四次:10位偶數:5, 5 ,得出結果:5
func gcdFinal(_ number: Int, _ number2: Int) -> Int {
if number2 == number {
return number
}
if number & 1 == 0 && number2 & 1 == 0 {
return gcdFinal(number >> 1, number2 >> 1) << 1 //都是偶數,除以2,最外層再乘以2
}else if number & 1 == 0 {
return gcdFinal(number >> 1, number2)
}else if number2 & 1 == 0 {
return gcdFinal(number2 >> 1, number)
}else {
//都是奇數的時候才用:更相減損術
let big = number > number2 ? number : number2
let small = number2 > number ? number : number2
return gcdFinal((big - small) >> 1, small)
}
}