求解最大公约数和最小公倍数问题

思路:

最大公约数问题也是一个非常典型的递归算法的应用。每次递归使得原来求两个大数之间的公约数转变成求两个稍微小点的数之间的公约数,要求转换的过程要保证不会改变公约数的值。这就要看其中转换的原理了。

原理从《几何原本》中得出--辗转相除。假设f(x, y) 表示x,y的最大公约数是g,而k = x/y,b= x%y,则g必能整出b。因为x = ky + b,b = x - ky,b/g = (x-ky)/g一定为整数,所以必有g整除b。

如下所示:

f(42, 30) = f(30, 12) = f(12, 6)= f(6, 0) = 6

代码如下:

[html]  view plain copy
  1. int gcd(int x , int y)  
  2. {  
  3.    return (y == 0 )?x :gcd(y , x % y) ;   
  4.       
  5. }  

非递归代码:

int gcd(int x,int y)
{
	int temp;
	while(y!=0)
	{
        temp=x;
        x=y;
		y=temp%y;
	}
	return x;
}


书中还引伸出辗转相减法,原理跟上面所述差不多。

代码如下:

[html]  view plain copy
  1. int gcd(int x , int y)  
  2. {  
  3.    if(x < y)  
  4.     return  gcd(y , x) ;    
  5.    else if(y == 0)  
  6.     return x ;  
  7.    else  
  8.     return gcd(x - y , y) ;          
  9.       
  10. }   

非递归代码:

int gcd(int n, int m)  
{  
    if(n==0)
       return m;
    while (m!= 0) 
	{  
        if (n > m)  
            n = n - m;  
        else  
            m = m - n;  
    }  
    return n;  
} 
或者:
int GetMaxCommonDivide_new(int n, int m)  
{  
	if(n<m)
	{
		n^=m;
		m^=n;
		n^=m;
		//n=n+m;
	        //m=n-m;
		//n=n-m;
	}
    while (m!= 0) 
	{  
        if (n > m)  
            n = n - m;  
        else  
            m = m - n;  
    }  
    return n;  
}

最后书中提到一种相除和相减相结合的方法,保证了不做过多冗余的步骤。这就是把2当作每次转换的数量级。

若x,y均为偶数,f(x,y) = 2*f(x/2,y/2) = 2*f(x>>1,y>>1)

若x为偶数,y为奇数,f(x,y) = f(x/2,y) = f(x>>1,y)

若x为奇数,y为偶数,f(x,y) = f(x,y/2) = f(x,y>>1)

若x,y均为奇数,f(x,y) =f(y,x-y)

此解法结合了上述两种方法:第一种方法递归次数相当少但每次取模挺耗时(到底耗时情况如何,我没有具体了解过,但肯定比加减法耗时些),而第二种递归可能会相当多,但每次运算都是减法运算, 很快。综合两者,用2为基数,可以保证递归次数不那么多,同时运算也快。

代码如下:

[cpp]  view plain copy
  1. int gcd(int x , int y)  
  2. {  
  3.   if(x < y)  
  4.      return gcd(y , x) ;  
  5.   if(y == 0)  
  6.      return x ;  
  7.    if(isEven(x)) //x为奇  
  8.    {  
  9.      if(isEven(y)) //y为奇             
  10.         return gcd(x - y, y) ;           
  11.      else         //y为偶  
  12.         return gcd(x , y >>1) ;              
  13.    }      
  14.    else         //x为偶  
  15.    {  
  16.       if(isEven(y)) //y为奇数              
  17.         return gcd(x >> 1, y) ;           
  18.      else         //y为偶  
  19.         return 2 * gcd(x >> 1, y >> 1) ;        
  20.            
  21.    }  
  22.       
  23. }  

求解最小公倍数:

从题面上看,好像我们需要求解的是两个题目,但其实就是一个题目。那就是求最大公约数?为什么呢?我们可以假想这两个数m和n,假设m和n的最大公约数是a。那么我们可以这样写:

    m = b *a;

    n = c * a;

    所以m和n的最小公倍数就应该是a*b*c啊,那不就是m * n / a,其中m和n是已知的,而a就是那个需要求解的最大公约数。所以就有了下面的代码,

[cpp]  view plain copy
  1. int GetMinCommonMultiple(int m, int n)  
  2. {  
  3.     assert(m && n);  
  4.   
  5.     return m * n / gcd(m, n);  
  6. }  



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值