**
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统计各种字符个数