GCD算法
GCD(get Greatest Common Divisor)獲得最大公約數的方法。
輾轉相除法
輾轉相除法, 又名歐幾里得算法,該算法的目的是求出兩個正整數的最大公約數。它是已知最古老的算法, 其產生時間可追溯至公元前 300 年前。
定理:兩個正整數 a 和 b (a>b),它們的最大公約數等于a除以 b的余數 c 和 b 之間的最大公約數。
例如:求10 和 25的最大公約數,可以先求25除以10商2余5,那么10和25的最大公約數,等同于10和5的最大公約數,依次類推。
代碼實現:
//迭代,輾轉相除法 public static int gcd(int a, int b) {//判斷a和b誰大if (a < b) {a ^= b;b ^= a;a ^= b;}int sum = a % b;while (sum != 0) {a = b;b = sum;sum = a % b;}return b; }//遞歸,輾轉相除法 public static int gcd2(int a, int b) {if (a < b) {a ^= b;b ^= a;a ^= b;}if (a % b == 0) {return b;}return gcd2(b, a % b); }更相減損術
更相減損術也是一種求最大公約數的算法。
原理:兩個正整數a和b(a>b),它們的最大公約數等于 a-b 的減值c和較小數b的最大公約數。
例如:求10 和 25的最大公約數,可以先求25減10的差是15,那么10和25的最大公約數,等同于10和15的差,依次類推。
代碼實現:
//迭代,更相減損術 public static int gcd3(int a, int b) {if (a < b) {a ^= b;b ^= a;a ^= b;}int sum = a - b;while (sum != 0) {a = b;b = sum;sum = a - b;}return b; }//遞歸,更相減損術 public static int gcd4(int a, int b) {if (a < b) {a ^= b;b ^= a;a ^= b;}if (a - b == 0) {return b;}return gcd4(b, a - b); }位運算優化
a和b的4種情況分析:
例如:求10和25的最大公約數步驟如下。
- 整數10通過移位,可以轉換成求5和25的最大公約數。
- 利用更相減損術,計算出25?5=20,轉換成求5和20的最大公約數。
- 整數 20通過移位,可以轉換成求5和10的最大公約數。
- 整數 10通過移位,可以轉換成求5和5的最大公約數。
- 利用更相減損術,因為兩數相等,所以最大公約數是 5。
代碼實現:
public static int gcd5(int a, int b) {//a,b相等直接返回if (a == b) {return b;}//四種情況if ((a & 1) == 0 && (b & 1) == 0) {// a,b都為偶數return gcd5(a >>> 1, b >>> 1) << 1;// 等價于 gcd5(a/2,b/2)*2} else if ((a & 1) == 0 && (b & 1) == 1) {// a為偶數,b為奇數return gcd5(a >>> 1, b);} else if ((a & 1) == 1 && (b & 1) == 0) {// a為奇數,b為偶數return gcd5(a, b >>> 1);} else {//都為奇數//進行一次更相減損術,求絕對值return gcd5(b, Math.abs(a - b));} }時間復雜度分析
- 暴力枚舉法:時間復雜度是 O(min(a,b))。
- 輾轉相除法:時間復雜度不太好計算,可以近似為 O(log(max(a,b))),但是取模運算性能較差。
- 更相減損術:避免了取模運算,但是算法性能不穩定,最壞時間復雜度為 O(max(a,b))。
- 更相減損術與移位相結合:不但避免了取模運算,而且算法性能穩定,時間復雜度為 O(log(max(a,b)))。
總結
- 上一篇: 数列求和推导
- 下一篇: 建立主DNS区域和辅助DNS区域的最佳实