zoukankan      html  css  js  c++  java
  • 最大公约数问题

    思路:

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

    原理从《几何原本》中得出--辗转相除。假设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 plaincopy

    1. int gcd(int x , int y)  
    2. {  
    3.    return (y == 0 )?x :gcd(y , x % y) ;   
    4.       
    5. }  

    书中还引伸出辗转相减法,原理跟上面所述差不多。只是碰到(100000000,1)这样的数时比较令人郁闷了

    代码如下:

    [html] view plaincopy

    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. }   

    最后书中提到一种相除和相减相结合的方法,保证了不做过多冗余的步骤。这就是把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 plaincopy

    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. 10.         return gcd(x - y, y) ;           
    11. 11.      else         //y为偶  
    12. 12.         return gcd(x , y >>1) ;              
    13. 13.    }      
    14. 14.    else         //x为偶  
    15. 15.    {  
    16. 16.       if(isEven(y)) //y为奇数              
    17. 17.         return gcd(x >> 1, y) ;           
    18. 18.      else         //y为偶  
    19. 19.         return 2 * gcd(x >> 1, y >> 1) ;        
    20. 20.            
    21. 21.    }  
    22. 22.       

    23. }  

  • 相关阅读:
    OSI安全体系结构
    PHP 二维数组根据相同的值进行合并
    Java实现 LeetCode 17 电话号码的字母组合
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 14 最长公共前缀
  • 原文地址:https://www.cnblogs.com/fickleness/p/3155040.html
Copyright © 2011-2022 走看看