算法篇:Java获取两个正整数的最大公约数

问题:Java获取两个数的最大公约数

1:暴力法

暴力法指的是什么呢?
很简单,就是从两数较小值开始遍历,当然最好是small/2.
代码较简单。

 /**
     * @param a
     * @param b
     * 暴力法:for循环
     * 如果是10000和10001时,需要循环4999次。太麻烦。
     */
    public static int getValues(int a,int b){
        int small=Math.min(a,b);
        int big=Math.max(a,b);

        if (big%small==0){
            return small;
        }

        for (int i=big/2;i>1;i--){
            if (small%i==0&&big%i==0){
                return i;
            }
        }

        return 1;
    }

这种方法上面的代码中也有提到,如果是10000和10001时,需要循环4999次,十分麻烦,这种方法的时间复杂度O(min(a,b));

2:辗转相除法(欧几里得算法)

辗转相除法基于一个定理,即:两个正整数a和b(a>b)的最大公约数与a除以b的余数与b的最大公约数相等。
具体做法:用a除以b得到余数c,将其转化为求b和c的最大公约数,然后b继续除以c获得d,求d与c的最大公约数。。。直到余数为0时停止。
看下代码实现:

 /**
     * @param a
     * @param b
     * @return
     * 辗转相除法(欧几里得算法)
     * a和b的最大公约数(a>b)等于a%b的余数与b的最大公约数
     * 问题:a和b的值过大时,取模运算性能太差
     */
    public static int getValues2(int a,int b){
        int small=Math.min(a,b);
        int big=Math.max(a,b);

        if (big%small==0){
            return small;
        }
       return getValues2(big%small,small);
    }

时间复杂度不太好计算。可以近似看成O(Log(max(a,b))).

3:更相减损法
更相减损法依据的定律:两个正整数a和b(a>b)的最大公约数与a-b的差与b的最大公约数相等。
所以具体的做法可以参照辗转相除法,利用递归获取。

/**
     * @param a
     * @param b
     * @return
     * 更相减损法
     *  a>b ,a-b=c和b的最大公约数等于a,b的最大公约数
     *
     *  问题:如果是10000和1的最大公约数,这时,递归的次数就有9999次,
     */
    public static int getValues3(int a,int b){
        int small=Math.min(a,b);
        int big=Math.max(a,b);

        if (small==big){
            return small;
        }
        return getValues3(big-small,small);
    }

相对于站桩相除法,减少了取模运算,但性能不太稳定,最坏时间复杂度为
O(max(a,b)。

4:优化的更新减损法

  /**
     * @param a
     * @param b
     * @return
     * 优化方法:对更相减损法进行位移操作。
     * 如果:a,b均为偶数。则gcd代表方法名,gcd(a,b)=2*gcd(a/2,b/2)=2*gcd(a>>1,b>>1);
     * 若a为奇数,b为偶数,则:gcd(a,b)=gcd(a,b>>1)
     * 若b为奇数,a为偶数,则:gcd(a,b)=gcd(a>>1,b)
     */
    public static int getValues4(int a,int b){
        if (a==b){
            return a;
        }
        if ((a&1)==0&&(b&1)==0){
            return getValues4(a>>1,b>>1)<<1;
        }else if ((a&1)==0&&(b&1)!=0){
            return getValues4(a>>1,b);
        }else if ((a&1)!=0&&(b&1)==0){
            return getValues4(a,b>>1);
        }else{
            int big=Math.max(a,b);
            int small=Math.min(a,b);
            return getValues4(big-small,small);
        }


    }

时间复杂度为O(Log(max(a,b)))。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值