歐幾里得算法核心:
gcd( a , b ) = gcd( b , a%b ) ,其中 gcd 表示 a 和 b 的最大公約數;
證明:
設 a 和 b 的最大公約數為 c ;
則有 c = gcd( a , b ) ;
設 a = x * c , b = y * c , 其中 x 與 y 互質 (因為 c 是最大公約數)
設 g = a%b = a - i * b = (x - i * y ) * c , 其中 i = [ a / b ] ,向下取整 ;
又 b = y * c , 且易得 x - i * y 與 y 互質;(下面會證明)
則有 b 與 g 的最大公約數為 c ,
又 g = a%b,
則 gcd( a, b ) = gcd( b , a%b );
接下來,證明 x - i * y 與 y 互質 ,
反證法:
設 x - i * y 與 y 不互質;
則 x - i * y 與 y 存在最大公約數 k ( k>1 ) ;
設 x - i * y = n * k, y = m * k, 其中 n 和 m 互質;
把 y = m * k, 代入 x 中 得:
x = (n + i * m ) * k
又 y = m * k ,
故 x 與 y 不互質 ,與 上述證明矛盾(前面設x,y是互質的);
所以 x - i * y 與 y 互質 ;
證畢;
gcd( a , b ) = gcd( b , a%b ),求解 a、b 的最大公約數 ,化為 求解b 、a%b 的最大公約數;
符合遞歸 大問題化成小問題 求解的特性(也可以用循環求解) ;
當前遞歸到 a%b == 0時(b 整除 a), 即 下一次遞歸的 b‘ = 0;
下一次遞歸 的 a’ ,即為當前層 的 b,為最大公約數;
掛代碼
1 int gcd(int a,int b) 2 { 3 return b?gcd(b,a%b):a; 4 }
復雜度分析
若 a=b, 那么最大公約數就是b ;
若 a < b , 那么 經過一次操作后 gcd(a ,b) = gcd( b, a%b) = gcd( b , a );
此時, a’ = b, b’ = a % b , a’ > b’ ;
則還是來看 a > b 的情況:
- a < 2 * b :
設 a = 2k (乘號省略),b = k + m (0<m<k);
第一次操作 變為 gcd( k+m , k-m ) ; // ( a%b = a - i b )
第二次操作 變為 gcd( k-m, r ) , r = (k+m)%(k-m) < k-m ;
k-m < k = a/2;
即兩次操作 數據量 最差變為原來的一半,所以復雜度為 O(2logN) ; - a > 2 * b :
設 a = 2k (乘號省略),b = k - m (0<m<k);
第一次操作就 變為 gcd (k-m, 2k%(k-m) );
數據量變為原來一半; - a=2 * b
最大公約數就是 max( b , 2) ;
綜上,最壞時間復雜度 約為 O(2logN) ,去掉常數即為 O(logN) , 底數為 2;