求最大公約數的兩種方法


輾轉相除法(歐幾里得算法)

歐幾里德算法又稱輾轉相除法,是指用於計算兩個正整數a,b的最大公約數。
時間復雜度為\(O(logN)\)

舉例

比如:30和42的最大公約數:
\(30 \mod 42 = 30\)
\(42 \mod 30 = 12\)
\(30 \mod 12 = 6\)
\(12 \mod 6 = 0\)
那么,30和42的最大公約數就是6。

代碼實現

int gcd(int a, int b) {
    while (b > 0) {
        c = a % b;
        a = b;
        b = c;
    }
    return a;
}

我們也可以使用遞歸的方法來實現。

int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

性能分析

由於輾轉相除法的時間復雜度為\(O(logN)\),在遇到比較大的數時(\(N\ge{10^{256}}\)),計算起來就會比較慢了。
這是因為輾轉相除法中含有模運算,當\(a\mod{b}\)時,相當於\(a\)減了\(k\)\(b\),也就是\(a - k * b\)
比如:
\(42 \mod 30 = 42 - 1 * 30\)
\(30 \mod 12 = 30 - 2 * 12\)

更相減損術

更相減損術是出自《九章算術》的一種求最大公約數的算法,它原本是為約分而設計的,但它適用於任何需要求最大公約數的場合。
最壞時間復雜度為\(O(N)\)

舉例

\(a>b\)時,用\(a-b\);當\(b>a\)時,用\(b-a\)
\(\gcd(30, 42) = \gcd(12, 30) = \gcd(18, 12) = \gcd(6, 12) = \gcd(6, 6)\)
\(a=b\)時,\(a\)就是這兩個數的最大公約數。

代碼實現

int gcd(int a, int b) {
    if (a == b) return a;
    else if (a > b) return gcd(a - b, b);
    else if (a < b) return gcd(b - a, a);
}

更相減損術二分版

上文提到,在兩個差距非常大的數(\(a=10000, b=1\)),使用更相減損術的時間復雜度為\(O(N)\)
這個算法的時間復雜度為\(O(logN)\)

代碼實現

可以使用按位與(&)來代替模運算。
例如:\((5)_{10} = (101)_{2}\),我們可以使用5&1來達到和模運算符一樣的效果。
我們知道,按位左移1位就是乘2,右移一位就是除以2。

int gcd(int a, int b) {
    if (a == b) return a;
    if ((a & 1) && (b & 1)) return gcd(a >> 1, b >> 1) << 2; // a和b都是偶數
    else if ((a & 1) && !(b & 1)) return gcd(a >> 1, b); // a是偶數b是奇數
    else if (!(a & 1) && (b & 1)) return gcd(a, b >> 1); // a是奇數b是偶數
    else if (!(a & 1) && !(b & 1)) { // a和b都是奇數
        if (a > b) return gcd(a - b, b);
        else if (a < b) return gcd(b - a, a);
    }
}

參考

感謝Vita小老師~
【算法小知識】如何求最大公約數(上)
【算法小知識】如何求最大公約數(下)


免責聲明!

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



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