Java實現:求兩個數的最大公約數



title: Java實現:求兩個數的最大公約數
tags:

  • java
  • 算法
    categories: 個人筆記
    copyright: true
    abbrlink: f202
    date: 2019-12-07 16:44:58

求解兩個數的最大公約數的幾種方法的比較

1. 暴力枚舉法

  • 優點:思路簡單

  • 缺點:運算次數多,效率低

  • 極端例子:求1000和10001的最大公約數

    需要計算1000/2 - 1 = 4999次

	// 暴力枚舉法
	public static int getGreatestCommonDivisor(int a,int b) {
        int big = a > b ? a : b;
        int small = a < b ? a : b;
        if (big % small == 0) {
            return small;
        }
        for (int i = small / 2; i > 1; i--) {
            if (big % i == 0 && small % i == 0) {
                return i;
            }
        }
        return 1;
    }

2. 輾轉相除法

  • 優點:運算次數少
  • 確定:模運算的開銷較大
    // 輾轉相除法
    public static int getGreatestCommonDivisor2(int a, int b) {
        int big = a > b ? a : b;
        int small = a < b ? a : b;
        if (big % small == 0) {
            return small;
        }
        return getGreatestCommonDivisor2(big % small, small);
    }

3. 更相減損法

  • 優點:避免了取模運算,采用減法運算,開銷較小
  • 缺點:算法性能不穩定,運算次數多
  • 極端例子:兩數相差懸殊時,如求1和10001的最大公約數,需要遞歸9999次
    // 更相減損法
    public static int getGreatestCommonDivisor3(int a, int b) {
        if(a == b){
	    return a;
	}
	int big = a > b ? a : b;
        int small = a < b ? a : b;
        return getGreatestCommonDivisor2(big - small, small);
    }

4. 結合輾轉相除法和更相減損法(位運算優化)

當a和b均為偶數時,gcd(a,b) = 2×gcd(a/2,b/2) = 2×gcd(a >>1,b>>1)。

當a為偶數,b為奇數時,gcd(a,b) = gcd(a/2,b) = gcd(a >>1,b)。

當a為奇數,b為偶數時,gcd(a,b) = gcd(a,b/2) = gcd(a ,b>>1)。

當a和b均為奇數時,先利用更相減損法運算一次,gcd(a,b) = gcd(a-b,b),此時a-b必然是偶數,接而繼續進行移位運算。

  • 優點:不但避免了取模運算,而且算法性能穩定
  • 缺點:代碼比較復雜
	//更相減損法(位運算優化)
    public static int getGreatestCommonDivisor4(int a, int b) {
        if (a == b) {
            return a;
        }
        if ((a & 1) == 0 && (b & 1) == 0) {// a,b都是偶數
            return getGreatestCommonDivisor4(a >> 1, b >> 1) << 1;
        } else if ((a & 1) == 0 && (b & 1) != 0) {// a為偶數,b為奇數
            return getGreatestCommonDivisor4(a >> 1, b);
        } else if ((a & 1) != 0 && (b & 1) == 0) {// a為奇數,b為偶數
            return getGreatestCommonDivisor4(a, b >> 1);
        } else {// a,b都是奇數
            int big = a > b ? a : b;
            int small = a < b ? a : b;
            return getGreatestCommonDivisor4(big - small, small);
        }
    }

5. 時間復雜度

  • 暴力枚舉法:O(min(a,b))
  • 輾轉相除法:近似於O(log(max(a,b)))
  • 更相減損法: O(max(a,b))
  • 結合輾轉相除法和更相減損法(位運算優化):O(log(max(a,b)))

6. 完整代碼

package gcd;

public class GreatestCommonDivisor {
    public static void main(String[] args) {
        System.out.println(getGreatestCommonDivisor(75, 180));
        System.out.println(getGreatestCommonDivisor2(75, 180));
        System.out.println(getGreatestCommonDivisor3(75, 180));
        System.out.println(getGreatestCommonDivisor4(75, 180));
    }

    // 暴力枚舉法
    public static int getGreatestCommonDivisor(int a,int b) {
        int big = a > b ? a : b;
        int small = a < b ? a : b;
        if (big % small == 0) {
            return small;
        }
        for (int i = small / 2; i > 1; i--) {
            if (big % i == 0 && small % i == 0) {
                return i;
            }
        }
        return 1;
    }

    // 輾轉相除法
    public static int getGreatestCommonDivisor2(int a, int b) {
        int big = a > b ? a : b;
        int small = a < b ? a : b;
        if (big % small == 0) {
            return small;
        }
        return getGreatestCommonDivisor2(big % small, small);
    }

    // 更相減損法
    public static int getGreatestCommonDivisor3(int a, int b) {
        int big = a > b ? a : b;
        int small = a < b ? a : b;
        if (big % small == 0) {
            return small;
        }
        return getGreatestCommonDivisor2(big - small, small);
    }

    //更相減損法(位運算優化)
    public static int getGreatestCommonDivisor4(int a, int b) {
        if (a == b) {
            return a;
        }
        if ((a & 1) == 0 && (b & 1) == 0) {// a,b都是偶數
            return getGreatestCommonDivisor4(a >> 1, b >> 1) << 1;
        } else if ((a & 1) == 0 && (b & 1) != 0) {// a為偶數,b為奇數
            return getGreatestCommonDivisor4(a >> 1, b);
        } else if ((a & 1) != 0 && (b & 1) == 0) {// a為奇數,b為偶數
            return getGreatestCommonDivisor4(a, b >> 1);
        } else {// a,b都是奇數
            int big = a > b ? a : b;
            int small = a < b ? a : b;
            return getGreatestCommonDivisor4(big - small, small);
        }
    }
}


參考《漫畫算法-小灰的算法之旅》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM