公约数:假设有两个数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;
}
}