Java经典例题50题 ----6 、Java求最大公约数与最小公倍数

**

Java求最大公约数与最小公倍数

**
【程序 6】
题目:输入两个正整数 m 和 n,求其最大公约数和最小公倍数。
/**在循环中,只要除数不等于 0,用较大数除以较小的数,将小的一个数作为下一轮循环的
大数,取得的余数作为下一轮循环的较小的数,如此循环直到较小的数的值为 0,返回较大
的数,此数即为最大公约数,最小公倍数为两数之积除以最大公约数。

其余的源码注释已经足够详细,所以这里就不再多说了。如实在有不明白的,可联系我:qq:2530318393,或者留言。
另外:写作不易,转载请声明所属~~~~~~~~

这是题目与他给的解题思路,他说的是欧几里得法(也就是辗转相除法)求最大公约数,而我去网上搜了下,还有更相减损法、stein法这两种方法求最大公约数。在程序中已经写出来了。其中我在做更相减损法的时候由于只看了这种方法的描述写的程序,没注意到在减的过程中会存在负值的情况,所以也是调试了下才发现。在程序中也提示了注意。

下面这里奉上我搜索到的方法的区别:

1、欧几里德算法与更相减损法比较:
(1)两者都是求最大公因数的方法,计算上辗转相除法以除法为主,更相减损术以减法为主,计算次数上辗转相除法计算次数相对较少,特别当两个数字大小区别较大时计算次数的区别较明显。

(2)从结果体现形式来看,辗转相除法体现结果是以相除余数为0则得到,而更相减损术则以减数与差相等而得到。

更相损减法在两数相差较大时,时间复杂度容易退化成O(N),而辗转相除法可以稳定在O(logN)。但辗转相除法需要试商,这就使得在某些情况下,使用更相损减法比使用辗转相除法更加简单。而stein算法便由此出现。

2、Stein算法与更相减损法比较
Stein算法很好的解决了辗转相除法中的这个缺陷,Stein算法只有整数的移位和加减法。下面就来说一下Stein算法的原理:

若a和b都是偶数,则记录下公约数2,然后都除2(即右移1位);
若其中一个数是偶数,则偶数除2,因为此时2不可能是这两个数的公约数了
若两个都是奇数,则a = |a-b|,b = min(a,b),因为若d是a和b的公约数,那么d也是|a-b|和min(a,b)的公约数。
Stein算法比辗转相除法更加快速,简易。它与每一次进行更相减损法得到的结果似乎存在着微妙的联系,通过下面的比较,可以发现两种算法之间的联系。

在这里插入图片描述
至于最小公倍数的求法也挺多的,但是知道了最大公约数,这两个数的乘积对最大公约数取商是最高效的。其中就可以通过将其分别分解质因数法。
分解质因(分解质因数可以参考另一篇文章,点这里)素法:
先分别分解准这几个数的质因数,则最小公倍数等于它们所有的质因数的乘积。

若有几个质因数相同,则比较这几个数中数中哪个数有该质因数的个数较多,假设为n个,则乘n次该质因数。
例如:36 = 2 * 2 * 3 * 3 270 = 2 * 3 * 3 * 3 * 5
不同的质因数是5,相同的质因数是⒉和3,2这个质因数在36中比较多,为两个,所以乘两次,3这个质因数在270个比较多,为三个,所以乘三次,则最小公倍数等于2 * 2 * 3 * 3 * 3 * 5 = 540…
至于最后一种短除法这里就不多做说明了,有兴趣的可以自行百度。

下面贴上我的源码:

/**
 * @program: 最大公约数与最小公倍数
 * @description: 求两个整数的最大公约数与最小公倍数程序入口
 * @author: Mr.XiaoShi
 * @create: 2020-09-08 16:20
 **/

import java.util.Scanner;


/**【程序 6】
 题目:输入两个正整数 m 和 n,求其最大公约数和最小公倍数。
 /**在循环中,只要除数不等于 0,用较大数除以较小的数,将小的一个数作为下一轮循环的
 大数,取得的余数作为下一轮循环的较小的数,如此循环直到较小的数的值为 0,返回较大
 的数,此数即为最大公约数,最小公倍数为两数之积除以最大公约数。* /
 **/
public class Program {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入两个整数:");
        int m = scanner.nextInt();
        int n = scanner.nextInt();
        System.out.println("辗转相除法(欧几里得法):"+get_ComDiv(m,n));
        System.out.println("更相减损法: "+get_ComDiv1(m,n));
        System.out.println("stein法:"+stein_Get_MaxComDiv(m,n));
        System.out.println("最小公倍数:"+get_LeaComMul(m,n));
    }
    /**
    *@Description: 辗转相除法(通过循环法、递归实现)
    *@Param:
    *@return:
    *@Author: your name
    *@date: 2020/9/8 0008
    **/
    static int get_ComDiv(int m,int n)
    {
        /*辗转 相除法通过普通的循环实现*/
        int tmp = m;  //排序,使m大于n
        if (m < n)
        {
            m = n;
            n = tmp;  //交换值
        }

        while(m % n != 0)  //循环,循环条件是大数对小数取余不为零时,即能整除时退出循环
        {
            /*除数作为新的被除数,余数作为新的除数,这里用tmp来保存m的值*/
            tmp = m;
            m= n;
            n = tmp % n;
        }
        return n;  //循环结束,找到最大公约数,返回它
        /*递归法*/
        /*return m > n ? m % n != 0? get_ComDiv(n,m % n) : n  :  //这里利用递归、三目运算符直接完成最大公约数的判断
                n % m != 0?   get_ComDiv(m,n % m) : m;*/

    }
    /*更相减损法*/
    /**
     * 第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
     *
     * 第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
     *
     * 则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
     *
     * 其中所说的"等数",就是最大公约数。求"等数"的办法是"更相减损"法。所以更相减损法也叫等值算法。
     * **/
    static int get_ComDiv1(int m,int n)
    {
        int tmp = m;  //交换值,保证m大于n
        if (m < n)
        {
            m = n;
            n = tmp;
        }
        tmp = 1;  //tmp置1,用来保存mn同时约掉的2的个数
        /*更相减损法*/
        if (m % n == 0)  //如果m对n能整除,n就是最大公约数,直接返回n
            return n;
        while ((m & 1) == 0 && (n & 1) == 0){  //循环判断是否是偶数,对2取余与与1相与运算等价,直到mn两者不都是偶数为止
            m = m >> 1;  //右移一位,相当于除2
            n = n >> 1;
            tmp = tmp << 1;   //左移一位,相当于乘2
        }

        for (int poor = (m - n); ; ) {  //循环,poor为差,(减数与差中较大的我称为减数,小的称为差)减数作为新的被减数,差作为新的减数,循环相减直到两者相等
            m = n;
            n = poor;
            poor = Math.abs(m - n);  //注意:这里一定要加绝对值,因为有可能存在减数比差值小的情况,这样相减就是负数,循环就会出问题
            if (poor == n)  //相等退出循环
                break;
        }
        return n*tmp;  //返回约数与最后差值的乘积
    }
    /*利用stein算法实现*/
    /**
     * Stein算法是一种计算两个数最大公约数的算法,是针对欧几里德算法在对大整数进行运算时,需要试商导致增加运算时间的缺陷而提出的改进算法。
     *
     * **/
    static int stein_Get_MaxComDiv(int m,int n)
    {
        int tmp = m;
        if (m < n)    //交换值进行排序,使得形参m大于n
        {
            m = n;
            n = tmp;
        }
        if (m - n == n)  //如过差等于减数就结束程序(结束递归)
            return n;
        if (((m & 1) == 0) && ((n & 1) == 0)){  //两个都是偶数
            return 2*stein_Get_MaxComDiv(m>>1,n>>1);  //返回约掉的2*递归的形参为新的m与n的返回值
        }
        else if ((m & 1) == 0)//m是偶数
        {
            return stein_Get_MaxComDiv(m>>1,n);  //m右移一位作为形参进行递归
        }
        else if((n & 1) == 0)//n是偶数
        {
            return stein_Get_MaxComDiv(m,n>>1);//n右移一位作为形参进行递归
        }
        return stein_Get_MaxComDiv(n,m-n);//都不是偶数就把减数、差作为参数传入进行递归
    }
    /**求最小公倍数**/
    static int get_LeaComMul(int m, int n){
        return (m*n)/stein_Get_MaxComDiv(m,n);  //乘积对最大公约数求商
    }
}

运行结果:

在这里插入图片描述
在这里插入图片描述
上一篇:利用嵌套完成成绩等级的判断

下一篇: Java统计各种字符个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值