编程之美读书笔记-最大公约数问题

来源:互联网 发布:淘宝有什么免费推广 编辑:程序博客网 时间:2024/05/16 14:20

题目:写一个程序,求两个正整数的最大公约数(Greatest Commom Divisor,GCD)。如果两个正整数都很大,有什么简单的算法吗?
解析:最简单的办法,就是直接用代码来实现辗转相除法,利用递归就能够很轻松的完成。

#include<iostream>using namespace std;int gcd(int x, int y){return (!y) ? x : gcd(y, x%y);}int main(){cout << gcd(42, 30) << endl;return 0;}
这个解法中我们用到了取模运算。对于大整数而言,取模运算是非常昂贵的开销,将成为整个算法的瓶颈。x和y的公约数与x-y和y的公约数是相同的,其最大公约数也是相同的。可以把大整数的取模运算转换成简单得多的大整数的减法。
#include<iostream>using namespace std;int gcd(int x, int y){if (x < y) return gcd(y, x);if (y == 0) return x;return gcd(x - y, y);}int main(){cout << gcd(30, 42) << endl;return 0;}
这个算法免去了大整数除法的繁琐,但是同样也有不足之处。最大的瓶颈就是迭代的次数比之前的算法多了不少,如果遇到(100000000,1)这类情况,就会相当令人郁闷了。从分析公约数的特点入手,简化计算。
1.如果y=k*y1,x=k*x1,那么gcd(y,x)=k*gcd(y1,x1);
2.如果x=p*x1,y%p!=0并且p是素数,那么gcd(y,x)=gcd(y,p*x1)=gcd(y,x1)。
2是一个素数,同时对于二进制表示的大整数而言,可以很容易地将除以2和乘以2的运算转换成移位运算,从而避免大整数除法,所以取p=2。
1.x和y均为偶数:gcd(y,x)=2*gcd(y>>1,x>>1);
2.x为偶数y为奇数:gcd(y,x)=gcd(y,x>>1);
3.x为奇数y为偶数:gcd(y,x)=gcd(y>>1,x);
4.x和y均为奇数:gcd(y,x)=gcd(y,x-y),x-y一定是一个偶数,下一步一定会有除以2的操作。
因此最坏时间复杂度为O(log2(max(x,y)))。
#include<iostream>using namespace std;int gcd(int x, int y){if (x < y) return gcd(y, x);if (y == 0) return x;if (x % 2){if (y % 2) return gcd(y, x - y);else return gcd(x, y >> 1);}else{if (y % 2) return gcd(x >> 1, y);else return gcd(x >> 1, y >> 1) << 1;}}int main(){cout << gcd(42, 30) << endl;return 0;}


0 0