《编程之美》笔记2 最大公约数
求两个正整数的最大公约数?
设要求x,y(x>y)的最大公约数,并且有 x = k*y+b.—— x % y = b
解法一:辗转相除法
一个基本的方法就是辗转相除法:x与y的最大公约数就是y和b的最大公约数。算法不断递归进行,直到b的值为0,此时y的值就是最大公约数。
使用递归方法:
int gcd(int x, int y)
{ if(x < y) return gcd(y, x); if(y <= 0) return x; return gcd(y, x%y); }
使用迭代方法:
int gcd(int x, int y) { if(x < y) {int temp = x; x = y; y = temp} while(y != 0) { int temp = x % y; x = y; y = temp; } return x; }
解法二:
取模运算的开销很大,可以采用减法来去掉取模运算,就是“《编程珠玑》第九章代码调优”的内容。
因为 m = x % y 就等价于
m = x-y;
while(m >= y)
m = m-y;
所以对于求最大公约数,直接将递归方法中的 return gcd(y, x%y); 变为 return gcd(x-y, y);就完了。
该方法的缺点就是迭代次数会变得很大。特别是x与y相差较大时。
解法三:
分析公约数的特点:
对x和y,若 y = k * y1, x = k * x1; 那么,f(x, y) = k * f(x1, y1).
另外,若x = p * x1,假设p是素数,并且 y%p != 0,(即y不能被p整除)那么f(x,y) = f(p*x1, y) = f(x1, 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>>1)
若x和y均为奇数,f(x,y) = f(y, x-y),这样x-y必定为偶数,下一步可以除以2进行缩小。
代码如下:
int gcd(int x, int y) { if(x < y) return gcd(y, x); if(y == 0) return x; if(isEven(x)) { if(isEven(y)) return gcd(x>>1, y>>1) << 1; else return gcd(x>>1, y); }else{ if(isEven(y)) return gcd(x, y>>1); else return gcd(y, x-y); } }