公约数:假设有两个数a,b,所谓的公约数就是能把a,b整除的最大整数。
求最大公约数的方法有很多。
方法1:穷举法,即通过循环找到一个2个数都能整除的数
public class Divide { public int getMaxDivide(int a,int b){ int value=0,min=0,max=0; if(a==b){ return a; } if(a>b){ max=a; min=b; }else { max=b; min=a; } for(int i=2;i<=min;i++){ if(a%i==0&&b%i==0){ value=i; } } return value; } public static void main(String[] args) { int a=60; int b=120; System.out.println(new Divide().getMaxDivide(a, b)); } }
方法2:欧几里德算法,公约数表示为f(a,b),并且有a>=b>0,欧几里德就给了我们一个很好的定理,f(a,b)=f(b,a%b)
我们来看下这个等式是怎么来的
设有 r=a/b ,q=a%b
所以就有 a=a/b*b+q ----(这里的a/b*b!=a ,原因就是我们用的是整数来计算的)
也就是a=r*b+q 变换一下有:q=a-r*b 设d=f(a,b),a/d=m,b/d=n;则 有q=dm-r*dn=d(m-rn)
所以q/d也为0;设d|q表示d是q的约数;以下相同;
又有d|b;所以有d|(b,q),设D是(b,q)的最大公约数,则会有d<=D=f(b,q);
再回到前面r=a/b,q=a%b这两个条件有
a=r*b+q,由于D|(b,q),所以D|a,所以有D|(a,b)
所以有D<=d=f(a,b),结合上部分就有d<=D <+d,及D=d;
所以得证;
通过递归的方法,我们很容易获得这样的算法:
public class Divide { public int getMaxDivide(int a,int b){ if(a<b){ int temp=a; a=b; b=temp; } if(b==0){ return a; } return getMaxDivide(b, a%b); } public static void main(String[] args) { int a=60; int b=120; System.out.println(new Divide().getMaxDivide(a, b)); } }
方法3:对于大数来言,取模运算代价很大,因此我们可以利用f(x,y)=f(x-y,y)
public class Divide { public int getMaxDivide(int a,int b){ if(a<b){ int temp=a; a=b; b=temp; } if(b==0){ return a; } return getMaxDivide(a-b, b); } public static void main(String[] args) { int a=60; int b=120; System.out.println(new Divide().getMaxDivide(a, b)); } }
这种方法和第二种方法相比,缺点在于递归迭代次数多。
方法3:
(1)如果y=k*y1,x=k*x1.那么有f(x,y)=k*f(x1,y1)
(2)如果x=p*x2,p为素数,并且y%p != 0,那么f(x,y) = f(p*x2,y) = f(x2,y)
于是我们得到下面的解决方法:
将p = 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)。这时x-y一定是偶数,下一步一定会除以2。
public static int moveCombe(int a,int b){ if(a<b){ return moveCombe(b, a); } if(0==b){ return a; } if(isTwo(a)){ if(isTwo(b)){ return moveCombe(a/2, b/2)*2; } return moveCombe(a/2, b); }else{ if(isTwo(b)){ return moveCombe(a, b/2); } return moveCombe(b, a-b); } } private static boolean isTwo(int a) { if(0==a%2){ return true; }else{ return false; } }