最大公约数问题

来源:互联网 发布:应对高考阅读优化卷下 编辑:程序博客网 时间:2024/05/23 15:57

最大公约数是个很基本的问题。欧几里德在他的著作里面给出了很高效的解法,辗转相除法。

假设f(x,y)表示x,y的最大公约数,取k=x/y,b=x%y,那么x=ky+b,这个能说明什么问题呢?

如果一个数能整除x和y,那么这个数也必定能整除y和b,并且x和y的最大公约数和y和b的最大公约数是相同的。

于是就有公式f(x,y)=f(y,x%y),于是就把原问题的最大公约数转化为两个更小数的最大公约数,直到一个数为0,另一个数则为最大公约数。

在这里遗留一个问题,就是没有看辗转相除法的证明,后面看初等数论时会补上。

举个例子:f(36,28)=f(28,8)=f(8,4)=f(4,0)=4

解法1代码:


考虑到上面解法1用到了模运算,对于大整数而言,取模运算开销很大,那么我们再来分析下是否不用模运算来改进算法?

分析上面的辗转相除法,如果一个数能够同时整除x,y,那么这个数一定能够同时整除x-y和y,也就是说f(x,y)=f(x-y,y)

改进之后的优点是:把大整数的取模运算转化为大整数的减法,节省了开销,但是也带来一个很大的缺点,那就是迭代的次数比解法1

多很多,特别是遇到(100000000,1)这种情况。

解法2代码:


是否就此结束了呢?解法1的缺点是取模运算复杂,解法2的缺点是减法运算次数多,那是否能够综合解法1和解法2得到最佳的算法?

我们设y=k*y1,x=k*x1,那么f(x,y)=k*f(x1,y1).如果x=p*x1,如果p为素数,那么y%p!=0,那么f(x,y)=f(p*x1,y)=f(x1,y).

我们知道2也是素数,我们下面选素数作为2的最大原因是一个2是一个神奇的数字,特别对于二进制的大整数来说,乘以2和除以2就可以

变成移位运算,免除大整数的除法运算,在这里不得不说我看到了数学之美,编程之美。

下面就用2来具体分析:

如果x和y都是偶数:f(x,y)=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(x-y,y)。

那么之后x-y又是偶数,下一步又会有除以2的操作。

f(36,28)=f(100100,11100)=2*f(10010,1110)=4*f(1001,111)

             =4*f(10,111)=4*f(111,10)=4*f(111,1)=4*f(110,1)

            =4*f(11,1)=4*f(10,1)=4*f(1,1)=4*f(0,1)=4*f(1,0)=4

解法3代码如下:


算法3巧妙地运用了移位运算和减法运算,避免了大整数的除法运算和取模运算,很大地提高了算法的效率。

我们也再次见证了位运算的强大!


0 0
原创粉丝点击