求两个正整数的最大公因数和最小公倍数
Posted fucktheperfect
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求两个正整数的最大公因数和最小公倍数相关的知识,希望对你有一定的参考价值。
求两个正整数的最大公因数和最小公倍数
今天做作业做到了一道求解两个数最大公因数的题,突然想总结一下求解的思路(目前为止自己知道的),那就开始吧。
两个正整数最大公因数和最小公倍数的关系
最小公倍数除以最大公因数等于两数之积
直接上图:
因此我们只要会求两个数的最大公因数,就可以很容易得到最小公倍数了,因此接下来我们主要求两个数的最大公因数
更相减损术
原理:
对于两个数91、168,设它们的最大公因数为m,则91,168都能被m整除(整除,即91%m==0),168-91=77,所以168可以写成91+77,91可以被m整除,所以77也能被m整除,因此可以转换为求91和77的最大公因数,再把91写成77+14,说明14也能被m整除,转换为求14和77的最大公因数,这样一直下去,最后转换为求14和7的最大公因数,再把14写成7+7,也就是求7和7的最大公因数,那就是7咯,写成算式就是:
168-91=77
91-77=14
77-14=63
63-14=49
49-14=35
35-14=21
21-14=7
14-7=7
代码实现:
#include<stdio.h>
int main()
{
int m, n;
scanf("%d%d", &m, &n);
int tmp = 0;//创建一个临时变量,用作m,n交换时的中间变量
while (n)
{
if (m < n)//如果m<n,交换两个数的值
{
tmp = m;
m = n;
n = tmp;
}
n = m - n;
m = m - n;
}
printf("%d", m);
}
结合着图片看,就会发现先令n=m-n,再令m=m-n,就相当于把m-n的值赋给n,把原来n的值赋给m,也就和我们上面的算式对应起来了
辗转相除法
原理:
辗转相除法原理与更相减损术原理相似,给定两个数168和91,168%91=77,就相当于168减去了一倍的91,91%77=14,就相当于91减去了一倍的77,77%14=7,相当于减去了5倍的14,相当于把五步和为一步!14%7=0,就说明最终结果就是7,结合上面更相减损数的转换思路理解!
代码实现:
#include<stdio.h>
int main()
{
int m, n,tmp=0;
scanf("%d%d", &m, &n);
while (n > 0)
{
tmp= m % n;
m = n;
n = tmp;
}
printf("%d", m);
return 0;
}
这种方法与上面的方法原理相似,理解了上面的这个就不算难理解,而且这个算法会节约一些时间,但是为什么这里不需要判断m<n的特殊情况?因为当m<n时,tmp=m%n就相当于tmp=m,而再加上m=n,n=tmp,就相当于交换了m,n的值
穷举法
原理:
对于两个数m,n的最大公因数,一定小于等于m,n中较小的那一个,我们只需从m,n中较小的数开始循环,找到第一个能整除m和n的那个数,即为最大公因数
代码实现:
#include<stdio.h>
int main()
{
int m, n;
scanf("%d%d", &m, &n);
int min = m > n ? m : n;//复习一下三目操作符
int i = 0;
for ( i = min; i >= 1; i--)
{
if (m % i == 0 && n % i == 0)
{
break;//一旦找到公因数就跳出循环,即为最大公因数
}
}
printf("%d", i);
}
Stein算法
原理:
大事化小
首先引进一个符号:gcd是greatest common divisor(最大公约数)的缩写,gcd( x,y ) 表示x和y的最大公约数。根据x,y的奇偶性我们可以进行转换。
下面三种情况中x,y均为奇数
两数都为偶数
则gcd( 2x , 2y )=gcd( x , y )*2
这个很容易明白
两数一奇一偶
y为奇数,所以y的所有因数都是奇数,所以二者的公因数也只能是奇数,所以gcd( 2x, y )=gcd( x , y )
两数都为奇数
这种情况乍一看没什么可以化小的方法,但是两个奇数的和、差都为偶数,这又引起我们的遐想!假设x>y
所以我们得到gcd( x,y )=gcd( (x+y)/2 ,(x-y)/2 )
那么接下来我们就可以把一个gcd( x , y )根据不同的情况化小,以求得答案
代码实现:
x&1表示x与1进行位运算,如果x&1=1,则x为奇数(建议复习一下&运算)
int Stein(int x,int y)
{
int m= 0,tmp=0;
if(x<y)
{
tmp=y;
y=x;
x=tmp;
}
while(x!=y)
{
if(x&1)
{
if(y&1)//x,y同为奇数时
{
y = (x-y)>>1;//右移一位,即y=(x-y)/2
x -= y;//即x=x-y
}
else//x为奇数,y为偶数时,这里x本就大于y,y/2后也必定大于y
{
y>>=1;//即y=y/2
}
}
else
{
if(y&1)//x为偶数,y为奇数
{
x>>=1;
if(x<y) //虽然x>y,但x/2后有可能小于y,再判断一次
{
tmp=y;
y=x;
x=tmp;
}
}
else//x,y都为偶数
{
x>>=1;
y>>=1;
m++;
}
}
}
return x<<m;//因为x,y同除以2后,最大公因数变为原来的一半,所以返回最大公因数时应该乘回来,而其它情况下x,y变化,最大公因数不变
}
int main()
{
int x,y;
scanf("%d%d",&x,&y);
int gcd= Stein(x,y);//接收最大公因数
printf("%d\\n",gcd);
return 0;
}
比如说我们代入168和91:
这其实和我们的递归思想有些相似,实际上这种算法也有递归写法,你可以试试哦!
以上是关于求两个正整数的最大公因数和最小公倍数的主要内容,如果未能解决你的问题,请参考以下文章