求最大公约数

求解两数的最大公约数有以下四种常见的方法:

1.暴力法

    public static int gcd1(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(small%i == 0 && big % i == 0){
                return i;
            }
        }
        return 1;
    }

2.辗转相除法

 /**
     * 辗转相除法
     *
     * 这条算法基于一条定理,两个正整数a,b(a>b),它们的最大公约数等于a除以b的余数c和b之间的最大公约数
     * 例如:10和25,25除以10商2余5,那么10和25的最大公约数等同于10和5的最大公约数。
     * 有了这条定理我们求最大公约数就变得简单。我们可以使用递归的方法把问题逐步简化
     * 首先,计算出a除以b的余数c,把问题简化成b和c的最大公约数;然后计算出b除以c的余数d,把问题转化成求c和d的最大公约数....
     * 以此类推,逐渐把两个较大整数之间的运算简化成两个较小整数之间的运算,直到两个数可以整除,或者其中一个数减小到1为止
     * @param a
     * @param b
     * @return
     */
    public static int gcd2(int a,int b){
        int big = a>b?a:b;
        int small = a<b?a:b;
        if(big%small == 0){
            return small;
        }
        return gcd2(big%small,small);
    }

3..更相减损术

 /**
     * 更相减损术
     *
     * 这条算法基于一条定理,两个正整数a,b(a>b),求它们的最大公约数等于a-b的差值c和b之间的最大公约数
     * 例如:10和25,25-10 = 15,那么10和25的最大公约数等同于10和15的最大公约数。
     * 有了这条定理我们求最大公约数就变得简单。我们可以使用递归的方法把问题逐步简化
     * 首先,计算出a-b的差值c,把问题简化成b和c的最大公约数;然后计算出b-c的差值d,把问题转化成求c和d的最大公约数....
     * 以此类推,逐渐把两个较大整数之间的运算简化成两个较小整数之间的运算,直到两个数相等,最大公约数就是最终两者相等的值
     *
     * @param a
     * @param b
     * @return
     */
    public static int gcd3(int a,int b){
        if(a == b) return a;
        int big = a>b?a:b;
        int small = a<b?a:b;

        return gcd2(big-small,small);
    }

4.更相减损术与移位相结合

/**
     * 更相减损术与移位相结合
     * 
     * 当a,b都为偶数时,gcd(a,b) =  2 * gcd(a/2,b/2) = gcd(a>>1,b>>1)<<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都为奇数时(a>b),先利用更相减损术运算一次gcd(a,b) = gcd(a-b,b),此时a-b必然是偶数,然后又可以利用移位运算
     * 例如计算10和25的最大公约数的步骤如下:
     * 1.整数10通过移位,可以转换成求5和25的最大公约数
     * 2.利用更相减损术,计算25-5 = 20,转换成求5和20的最大公约数
     * 3.整数20通过移位,可以转换成1求10和5的最大公约数
     * 4.整数10通过移位,可以转换成求5和5的最大公约数
     * 5.利用更相减损术,以为两数相等,所以最大公约数是5
     *
     * @param a
     * @param b
     * @return
     */
    public static int gcd4(int a,int b){
        if(a == b) return a;
        if((a&1) == 0 && (b&1)==0){
            return gcd4(a>>1,b>>1)<<1;
        }else if((a&1) == 0 && (b&1)!=0){
            return gcd4(a>>1,b);
        }else if((a&1)!=0 && (b&1) == 0){
            return gcd4(a,b>>1);
        }else {
            int big = a>b?a:b;
            int small = a<b?a:b;
            return gcd2(big - small, small);
        }
    }

四种方法时间复杂度比较:

1.暴力法:时间复杂度为O(min(a,b))
2.辗转相除法:时间复杂度不好计算,可以近似的看成O(log(max(a,b))),取模性能较差
3.更相减损术:避免取模运算,但是算法想能不稳定,最坏时间复杂度为O(max(a,b))
4.更相减损术与移位相结合:不但避免了取模运算,而且算法性能稳定,时间复杂度为O(log(max(a,b)))

原文地址:https://www.cnblogs.com/du001011/p/10822122.html