每日一题(75) - 最大公约数问题

来源:互联网 发布:各大编程语言效率比较 编辑:程序博客网 时间:2024/05/01 11:48

题目来自编程之美

题目


注意:这里不考虑负数。

思路(1)辗转相除法

思想:

参数要求:无要求,x >= y 或 y >= x均可gcd(x,y) = gcd(y ,x % y);
原理:

假设 x = ky + b,其中 k = x/y,b = x%y.

则,b = x - ky

假设 整数t同时整除x和y,则

式子两边同时除以t,得

b / t = (x - ky) / t = 整数

则,b = x%y 也能整除t。

即,x 和 y的最大公约数 等于 y和 x%y 的最大公约数。

注意,这里我们只考虑正数,即有x > y。

此时,就有了 gcd(x,y) = gcd(y ,x % y),y > 0;

在式子中,右边的参数参数都在减小,即把原问题转换为求两个更小数的公约数了,一直到其中一个数为0,则另外一个数就为其最大公约数。

举例:

30 和 12 的最大公约数 等于 12 和 6 的最大公约数。

12 和 6  的最大公约数 等于 6 和  0 的最大公约数。

6  和 0  的最大公约数 等于 6,则30 和 12 的最大公约数 等于 6。

特点:计算次数比较少,但是取模运算运算代价昂贵,尤其是针对大数据。

代码:

int Gcd(int x,int y){return y == 0 ? x : Gcd(y,x % y);}
代码注意事项:

(1)传参时,不需要要求x > y。

(2)需要注意程序的形参(x,y)和入口参数的顺序(y,x%y)。

思路(2)两数相减法

思想:

参数要求:有要求,x >= ygcd(x,y) = gcd(y,x - y);
举例:

<1> 30 和 12 的最大公约数 等于 12 和 18 的最大公约数。

<2> 18 和 12 的最大公约数 等于 12 和 6 的最大公约数。

<3> 12 和6 的最大公约数 等于 6 和 0 的最大公约数。

<4> 6 和 0 的最大公约数 等于 6,则30 和 12 的最大公约数 等于 6。

特点:计算次数比较多,但是不需要取模运算。

代码:

int Gcd(int x,int y){if (y > x){return Gcd(y,x);/*要求x > y*/}return y == 0 ? x : Gcd(y, x - y);}

代码注意事项:

(1)传参时,要求x > y。

(2)在程序执行过程中,也有可能出现 x < y 的情况(如举例中第一次计算就出现了),因此需要在程序中写交换语句。

思路(3)辗转相除法与相减结合

引入的原因:结合两种方法,使得迭代次数少 且 又没有取模等代价昂贵的运算,继而快速求解大数据的最大公约数。

思路:

运用取模运算的性质:

对于 x 和 y 来说,

(1)如果x = k * x1 且 y = k * y1,则x 和 y的最大公约数等于 k * (x1 和 y1的最大公约数)。

(2)如果x = p * x1 且 p 素数 且 y % p != 0,则x 和 y的最大公约数等于x1 和 y的最大公约数。

在程序中,需要寻找一个类似(2)的p,即需要判断p是否是x或者y的因子。

由于在程序中判断2是否是一个数的因子还是比较方便的,这里就令p = 2。

为啥是方便的呢?

判断2是否为x的因子,即判断x是否为偶数。可以直接使用位运算,来判断x是否为偶数,很方便。

这样,我们可以通过除2来减少计算次数。

具体思路:

如果 x为偶,y为偶,则gcd(x,y) =2 * gcd(x >> 1,y >> 1)。

如果 x为偶,y为奇,则gcd(x,y) = gcd(x >> 1,y)。

如果 x为奇,x为偶,则gcd(x,y) = gcd(x,y >> 1)。

如果 x为奇,x为奇,则gcd(x,y) = gcd(y,x - y)。

在执行gcd(y,x - y)后,这俩参数一个为奇数,一个为偶数,下一步就又有除2操作了。

注意:当x和y均为偶数时,别忘了乘以2。

分析:

为啥呢:如果x为2的幂且y = 3,则可以一直除2,一直到最后。

举例:

<1> 30 和 12 的最大公约数 等于 15 和 6  的最大公约数 * 2

<2> 15 和 6  的最大公约数 等于 15 和 3  的最大公约数。

<3> 15 和 3  的最大公约数 等于 3  和 12 的最大公约数。

<4> 12 和 3  的最大公约数 等于 6  和 3  的最大公约数。

<5> 6  和 3  的最大公约数 等于 3  和 3  的最大公约数。

<6> 3  和 3  的最大公约数 等于 3  和 0  的最大公约数。

<7> 3  和 0  的最大公约数 等于 3,则30 和 12 的最大公约数 等于 6

注意:别忘了乘以2.

代码:

int Gcd(int x,int y){if (x < y){return Gcd(y,x);/*形参要求 x > y */}if (y == 0){return x;}if ((x & 1) == 0) //x为偶数{if ((y & 1) == 0) //x为偶数,y为偶数{return Gcd(x >> 1,y >> 1) << 1;//别忘了乘以2}else //x为偶数,y为奇数{return Gcd(x >> 1,y);}}else{if ((y & 1) == 0) //x为奇数,y为偶数{return Gcd(x,y >> 1);}else //x为奇数,y为奇数{return Gcd(y,x - y);}}}

代码注意事项:

(1)传参时,要求x > y。

(2)在程序执行过程中,也有可能出现 x < y 的情况,因此需要在程序中写交换语句。


原创粉丝点击