求两数的最大公约数算法

最大公约数,也称最大公因数、最大公因子,指两个或多个整数共有约数中最大的一个;

a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也有同样的记号;

 求最大公约数有多种方法,常见的有质因数分解法、短除法、欧几里得算法(又称辗转相除法)更相减损法

资料来源:百度百科-最大公约数 链接

质因数分解法&短除法较依赖计算者,灵活性也很大,步骤不固定,本文作者仅使用Java代码实现欧几里得算法(又称辗转相除法)&更相减损法,具体如下:

一、欧几里得算法(又称辗转相除法)

package algorithm.maxCommonDivisor;

/**
 * 求两个数的最大公约数
 * 欧几里得算法(又称辗转相除法)
 *
 * @author XUQIANG_DUAN
 * @date 2019/7/29
 * @time 9:21
 */
public class EuclideanAlgorithm {

    /**
     * 辗转相除法
     *
     * @param a
     * @param b
     * @return 最大公约数
     */
    private static int euclidMethod(int a, int b) {
        /**
         * 大值&小值
         */
        int maxI = a > b ? a : b;
        int minI = a > b ? b : a;
        /**
         * 余数
         */
        int remainder = maxI % minI;
//        System.out.println("余数为:" + remainder);
        /**
         * 余数为零,小值为最大公约数
         * 余数为一,一为最大公约数
         * 大值&小值的最大公约数与小值与余数的最大公约数相同
         */
        if (remainder == 0) {
            return minI;
        } else if (remainder == 1) {
            return remainder;
        } else {
            return euclidMethod(minI, remainder);
        }
    }

    /**
     * 运行时间&结果记录
     * currentTimeMillis 为毫秒时间戳
     * nanoTime 为纳秒时间戳
     * 1 秒 = 10^3 毫秒
     * 1 秒 = 10^9 纳秒
     *
     * @param a
     * @param b
     */
    private static void timeConsume(int a, int b) {

//        long start = System.currentTimeMillis();
        long nstart = System.nanoTime();
        System.out.println("(" + a + ", " + b + ") | result = " + euclidMethod(a, b));
//        long end = System.currentTimeMillis();
        long nend = System.nanoTime();
//        System.out.println("共耗时(单位:ms):" + (end - start) + " | 结束点:" + end + " | 开始点:" + start);
        System.out.println("共耗时(单位:ns):" + (nend - nstart) + " | 结束点:" + nend + " | 开始点:" + nstart);

    }

    public static void main(String[] args) {

        timeConsume(55, 55);
        timeConsume(66, 55);
        timeConsume(10000, 10001);
        timeConsume(10000, 10003);
        timeConsume(1350, 1266);
        timeConsume(1000000, 1000003);

    }
}

代码运行结果如下:
...

(55, 55) | result = 55
共耗时(单位:ns):438614 | 结束点:89819135569674 | 开始点:89819135131060
(66, 55) | result = 11
共耗时(单位:ns):21049 | 结束点:89819135643629 | 开始点:89819135622580
(10000, 10001) | result = 1
共耗时(单位:ns):17636 | 结束点:89819135685727 | 开始点:89819135668091
(10000, 10003) | result = 1
共耗时(单位:ns):23325 | 结束点:89819135732376 | 开始点:89819135709051
(1350, 1266) | result = 6
共耗时(单位:ns):31858 | 结束点:89819135789265 | 开始点:89819135757407
(1000000, 1000003) | result = 1
共耗时(单位:ns):27876 | 结束点:89819135849567 | 开始点:89819135821691

Process finished with exit code 0

二、更相减损法

package algorithm.maxCommonDivisor;


/**
 * 求两个数的最大公约数
 * 更相减损法
 *
 * @author XUQIANG_DUAN
 * @date 2019/7/29
 * @time 10:24
 */
public class Subtraction {

    private static int subMethon(int a, int b) {

        int result = 1;
        /**
         * 大值&小值
         */
        int maxI = a > b ? a : b;
        int minI = a > b ? b : a;
        /**
         * 大值&小值都为偶数,先简约
         */
        while (maxI % 2 == 0 && minI % 2 == 0) {
            result *= 2;
            maxI /= 2;
            minI /= 2;
        }
        /**
         * 差值
         */
        int sub = maxI - minI;
//        System.out.println("差值为:" + sub + " | 大值为:" + maxI + " | 小值为:" + minI + " | 结果为:" + result);
        if (sub == 0) {
            result *= minI;
        } else if (sub == 1) {
            result *= 1;
        } else {
            result *= subMethon(minI, sub);
        }

        return result;
    }

    /**
     * 运行时间&结果记录
     * currentTimeMillis 为毫秒时间戳
     * nanoTime 为纳秒时间戳
     * 1 秒 = 10^3 毫秒
     * 1 秒 = 10^9 纳秒
     *
     * @param a
     * @param b
     */
    private static void timeConsume(int a, int b) {

//        long start = System.currentTimeMillis();
        long nstart = System.nanoTime();
        System.out.println("(" + a + ", " + b + ") | result = " + subMethon(a, b));
//        long end = System.currentTimeMillis();
        long nend = System.nanoTime();
//        System.out.println("共耗时(单位:ms):" + (end - start) + " | 结束点:" + end + " | 开始点:" + start);
        System.out.println("共耗时(单位:ns):" + (nend - nstart) + " | 结束点:" + nend + " | 开始点:" + nstart);
    }

    public static void main(String[] args) {
        timeConsume(5,55);
        timeConsume(66,55);
        timeConsume(10000,10001);
        timeConsume(10000,10003);
        timeConsume(1350, 1266);
        timeConsume(1000000, 1000003);
    }
}

代码运行如下:

...
(5, 55) | result = 5
共耗时(单位:ns):445440 | 结束点:90158027966585 | 开始点:90158027521145
(66, 55) | result = 11
共耗时(单位:ns):43235 | 结束点:90158028074105 | 开始点:90158028030870
(10000, 10001) | result = 1
共耗时(单位:ns):31289 | 结束点:90158028144648 | 开始点:90158028113359
(10000, 10003) | result = 1
共耗时(单位:ns):753209 | 结束点:90158028942799 | 开始点:90158028189590
(1350, 1266) | result = 6
共耗时(单位:ns):39253 | 结束点:90158029022443 | 开始点:90158028983190
Exception in thread "main" java.lang.StackOverflowError 【栈内存溢出异常】
    at algorithm.maxCommonDivisor.Subtraction.subMethon(Subtraction.java:40)

...

Disconnected from the target VM, address: '127.0.0.1:54677', transport: 'socket'

Process finished with exit code 1

结束语

更相减损法较辗转相除法时间&空间复杂度都较高,也极易发生栈内存溢出异常,原因也不难理解,乘除为加减的高级运算同时效率也倍增。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值