最大公約數和最小公倍數,最全!

兩個數的最大公約數 GCD

整數 a 和 b 的最大公約數記爲 gcd a , b)

1.輾轉相除法

  • 遞歸版
int GCD(int a,int b)
{
    return b == 0 ? a : GCD(b , a % b);
}

短小精悍

  • 非遞歸版
int GCD(int a,int b)
{
    while(b != 0)
    {
        int n = a % b;
        a = b;
        b = n;
    }
    return a;
}

時間複雜度差不多是O(log2n),非常快了

2.內置函數

  • 先引入頭文件 #include<algorithm>
std::__gcd(a,b);
  • 內部實現
template<typename EuclideanRingElement>
EuclideanRingElement __gcd(EuclideanRingElement m, EuclideanRingElement n)
{
    while (n != 0)
    {
        EuclideanRingElement t = m % n;
        m = n;
        n = t;
    }
    return m;
}

內置的算法跟上面的非遞歸版一樣!

兩個數的最小公倍數 LCM

整數 a 和 b 的最小公倍數記爲 lcm(a , b)

顯然有 gcd(a,b) 整除 lcm(a,b)
那麼可以知道 lcm(a,b) = a * b / gcd(a,b)

  • 代碼
int LCM(int a,int b)
{
    return a * b / gcd(a,b);
}

gcd(a,b)參考前面

多個數的最大公約數

求多個數的最大公約數,考慮到c++的泛型編程,就很容易實現。

具體實現思路爲倒着一個一個的求出第一個數的因數,依次拿其餘的數除以該因數,若所有的數都能除盡該因數,則該因數即爲所求的最大公因數。倒着求因數保證了"最大"。

  • 泛型實現求最大公約數
template <typename RAIter>
int gcd_s(RAIter _begin, RAIter _end)
{
    bool _isDivisible(true),_flag(false);
    for(int i = *_begin;i>=2;--i){//倒着求_begin的因數
        if(*_begin % i == 0){
            _flag = true;
            for(RAIter _next = _begin+1;_next!=_end;++_next){//依次判斷_begin的因數能不能整除其餘的數
                if(*_next % i != 0){
                    _isDivisible = false;
                    break;
                }
            }
        }
        else
            _flag = false;
        if(_isDivisible && _flag)//若能整除其餘的所有數,則該因數即爲最大公因數
            return i;
        _isDivisible = true;
    }
    return 1;//所有因數都不滿足,說明1是最大公因數
}

由上面的分析不難看出,每次是求的第一個數的因數,那麼如果區間第一個數是所有數裏面最小的,那麼代碼運行速度肯定是最快的,所以使用前讓區間第一個數字儘量的小。使用前可以用內置函數 sort() 排一下序

  • 使用方法
	vector<int> a{9,108,63,57,12};
    array<int,5> b{9,108,63,57,12};
    int c[5]{9,108,63,57,12};

    cout<< gcd_s(a.begin(),a.end()) <<endl;
    cout<< gcd_s(b.begin(),b.end()) <<endl;
    cout<< gcd_s(c,c+5) <<endl;//普通數組調法[數組名,數組名+長度)
    cout<< gcd_s(begin(c),end(c)) <<endl;//普通數組也可以這樣調

多個數的最小公倍數

考慮兩個數的最小公倍數求法,自然想到將所有數乘起來除以最大公約數。但是很遺憾這樣並不可行,例如9,10,5的最大公約數爲1,而最大公倍數爲90 ≠ 9 × 10 × 5 ÷ 1

但是基於這個思路我們可以想到先求出前兩個數的最小公倍數,這樣問題規模就從n變爲n-1,重複這個步驟即可得到最終答案。

  • 泛型求最小公倍數
template <typename RAIter>
int lcm_s(RAIter _begin,RAIter _end)
{
    int result = *_begin * *(_begin+1) / __gcd(*_begin,*(_begin+1));
    for(RAIter _next = _begin+2;_next!=_end;++_next)
        result = result * (*_next) / __gcd(result,*_next);
    return result;
}

調用方法與上面的泛型最大公約數一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章