最大公约数问题的基本求法是辗转相除法,辗转相除法的思想是这样的:首先两个数x,y,假设x>y,那么x = ky+b。x,y的公约数一定能够同时整除y,b。那么x,y的最大公约数一定就是y,b的最大公约数,如此不断的转换,直到b为0为止。

  代码如下:

1 public int gcd(int x,int y){
2      return (!y)?x:gcd(y,x%y);  
3 }

  由于取模运算是非常昂贵的开销,所以会成为程序的瓶颈,需要采用一些办法不使用取模操作。换一种思路,如果一个数能同时整除x,y,那么必然能够同时整除x-y和y,那么x,y的最大公约数一定就是x-y和y的最大公约数。如此循环,直到一方为0为止,为了防止出现x-y是负值的情况,所以要保证函数中的x一定大于y,如果x-y《y,那么就gcd(y,x-y)。具体代码如下:

  

 1 public int gcd(int x,int y){
 2      if(x<y){
 3          return   gcd(y,x)
 4       }  
 5      if(y==0){
 6          return x;
 7      }else{
 8         return gcd(x-y,y);
 9     }
10 }

  以上的代码用减法代替了除法,能够有更好的执行效率。但是迭代次数也增多了很多,在极端情况下,比如(10000000,1)这种情况,就相当糟糕了。

  因此需要一种方式,同时减少除法运算和减法运算。

  这就是解法三,不过我觉得一般情况下基本上是想不到解法三的做法的,假设k是素数,x=k*x1,y%k!=0,那么x,y的公约数中,肯定不含k,因此x/=k;如果两个都含k,那么x,y的公约数就等于k*gcd(x/=k,y/=k)。

  2就是一个最简单的素数,同时在计算机中对2的操作可以转变为左移和右移的操作,非常的节省开销。

  下面就针对不同的情况进行分析:

  如果x能被2整除,y不能,那么gcd(x>>1,y)。x不能被2整除,y能被2整除同理。

  如果x,y都能被2整除,则将这个2提取出来,2*gcd(x>>1,y>>1)。

  如果x,y都不能被2整除,那么就用解法二的方法,算x和x-y的公约数,由于x,y为奇数,所以x-y一定是偶数,所以一定能变成上面的情况。具体代码如下:

  

 1 public int gcd(int x,int y){
 2      if(x<y){
 3           return gcd(y,x);
 4      }  
 5      if(y==0)
 6           return x;
 7      if(x%2!=0){
 8          if(y%2!=0){
 9               return gcd(x-y,y)
10          }else{
11               return gcd(x,y>>1);
12          }
13      }else{
14          if(y%2!=0){
15              return gcd(x>>1,y);
16          }else{
17              return gcd(x>>1,y>>1)<<1;
18          }
19      }    
20 }

  另外为了增加适用性,在gcd的参数中不一定是限定int类型,可以使BigInteger类型的