求两个正整数的最大公因数和最小公倍数

求两个正整数的最大公因数和最小公倍数

今天做作业做到了一道求解两个数最大公因数的题,突然想总结一下求解的思路(目前为止自己知道的),那就开始吧。

两个正整数最大公因数和最小公倍数的关系

最小公倍数除以最大公因数等于两数之积
直接上图:
《求两个正整数的最大公因数和最小公倍数》
因此我们只要会求两个数的最大公因数,就可以很容易得到最小公倍数了,因此接下来我们主要求两个数的最大公因数

更相减损术

原理:

对于两个数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:
《求两个正整数的最大公因数和最小公倍数》
这其实和我们的递归思想有些相似,实际上这种算法也有递归写法,你可以试试哦!

    原文作者:algorithmwqy
    原文地址: https://blog.csdn.net/csdnwqy030429/article/details/120942502
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞