求两个正整数的最大公约数
方法一:
辗转相除法
假设两个正整数x,y ,令x/y=p ,x%y=q 即 x=p* y +q 则 如果一个数能整除x,y 则一定能够整出y 和q 如果一个数能够整除y和q 则一定能够整除x,y ,所以x,y和y ,q具有相同的公约数
gcd(x,y)=gcd(y,x%y)....
比如 x=18 y=12
gcd(18,12)=gcd(12,6)=gcd(6,0) 因此最大公约数为非0的数 6
显然可以用递归的方法实现:
int gcd(int x,int y)
{
if(x==0)
return y;
if(y==0)
return x;
return gcd(y,x%y);
}
方法二:
类似辗转相除法 如果一个数能整除x,y 则一定能够整出y 和x-y 如果一个数能够整除y和x-y 则一定能够整除x,y ,所以x,y和y ,x-y具有相同的公约数
用递归实现:
int gcd1(int x,int y)
{
if(x<y)
return gcd1(y,x);
if(y==0)
return x;
else
return gcd1(x-y,y);
}
对于很大的数求最大公约数 方法一不适合 而对于方法二 将取余转换为减法 但是迭代次数太多 因此都不适合求大数的公约数
对于x ,y ,如果y=k* y1 x= k*x1 则gcd(x,y)= k*gcd(x1,y1)
如果x=p *x1 假设p为素数 且 y%p!=0 则 gcd(x,y)=gcd(p*x1,y)=gcd(x1,y)
我们可以利用上述两条性质对算法进行改进,对于最简单的素数2 我们很容易对一个数 将乘以2和除以2转换为移位运算
令p=2
若x,y均为偶数 则gcd(x,y)=2*gcd(x/2,y/2)=2*gcd(x>>1,y>>1)
若x为偶数y为奇数 f(x,y)=gcd(x/2.y)=gcd(x>>1,y)
若x为奇数 y为偶数 f(x,y)=gcd(x,y/2)=gcd(x,y>>1)
若x,y同为奇数 f(x,y)=gcd(x-y,y)
那么在gcd(x,y)=gcd(x,x-y)后 x-y肯定为偶数 下一步一定会有除以2的操作
最坏情况下时间复杂度为O(log(max(x,y))
int gcd2(int x,int y)
{
if(x<y)
return gcd2(x,y);
if(y==0)
return 0;
else
{
if(x%2==0)
{
if(y%2==0)
return gcd2(x>>1,y>>1);
else
return gcd2(x>>1,y);
}
else
{
if(y%2==0)
return gcd2(x,y>>1);
else
return gcd(y,x-y);
}
}
}