2.7 编程之美--最大公约数的3种解法[efficient method to solve gcd problem]

【本文链接】

http://www.cnblogs.com/hellogiser/p/efficient-method-to-solve-gcd-problem.html

【题目】

  求两个正整数的最大公约数Greatest Common Divisor (GCD)。如果两个正整数都很大,有什么简单的算法吗?例如,给定两个数1 100 100 210 001, 120 200 021,求出其最大公约数。

【解法】



【1. 辗转相除法】

辗转相除法:f(x,y) = f(y , x % y)(x>y)

f(42,30) = f(30,12) = f(12,6) = f(6,0) = 6

【代码】

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/7/8
*/

int gcd(int x, int y)
{
    if(x < y)
        return gcd(y, x);
    if(y == 0)
        return x;
    else
        return gcd(y, x % y);
}

此方法中用到了取模运算,对于大整数而言,取模运算(其中用到了除法)开销是非常昂贵的,将成为整个算法的瓶颈。



【2. 辗转相减法】

辗转相减法:f(x,y) = f(y, x-y) (x>y)

f(42,30) = f(30,12) = f(12,18) = f(18,12) = f(12,6)=f(6,6)=f(6,0)=6

【代码】

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/7/8
*/

int gcd(int x, int y)
{
    if(x < y)
        return gcd(y, x);
    if(y == 0)
        return x;
    else
        return gcd(y, x - y);
}

这个算法免去了大整数除法的繁琐,但同样也有不足之处。最大的瓶颈是迭代的次数过多,如果出现(1 000 000 000,1)这类情况,那就相当让人郁闷了。



【3. 奇偶法】

奇偶法:

此种方法是将解法1)和解法2)结合起来,降低计算复杂度的同时也降低迭代次数。

1:若 x, y均为偶数,f (x,y) = 2 * f(x / 2, y / 2) = 2 * f(x >> 1, y >> 1)

2:若x为偶,而y为奇,f (x , y )  = f (x / 2, y) = f ( x >> 1, y)

3:若x为奇,y为偶,f ( x, y)  = f (x , y / 2) = f(x , y >> 1)

4:若x,y均为奇,f ( x, y ) = f (y , x - y)

在f(x, y) = f(y, x - y)之后,(x - y)是一个偶数,下一步一定会有除以2的操作。

因此最坏情况下时间复杂度为O(log2 (max(x,y)))。

f (42 , 30 ) = 2 * f (21,15)

= 2 * f (15,6)

= 2 * f (15,3)

= 2 * f (3,12)  =2 * f (12,3)

= 2 * f (6,3)

= 2 * f (3,3)

= 2 * f (3,0)

= 2 * 3

= 6

代码】

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/7/8
*/

bool IsEven(int x)
{
    return (x & 0x1) == 0;
}

int gcd(int x, int y)
{
    if(x < y)
        return gcd(y, x);
    if(y == 0)
        return x;
    else
    {
        if(IsEven(x))
        {
            if(IsEven(y)) //case 1,x,y均为偶数
                return 2 * gcd(x >> 1, y >> 1);
            else  //case 2,x为偶,y为奇
                return gcd(x >> 1, y);
        }
        else
        {
            if(IsEven(y)) //case 3,x为奇,y为偶
                return gcd(x, y >> 1);
            else  //case 4,x,y均为奇
                return gcd(y, x - y);
        }
    }
}

【参考】

http://blog.csdn.net/ajioy/article/details/7478008

http://blog.csdn.net/rein07/article/details/6739688

【本文链接】

http://www.cnblogs.com/hellogiser/p/efficient-method-to-solve-gcd-problem.html

2.7 编程之美--最大公约数的3种解法[efficient method to solve gcd problem]

时间: 2024-10-18 17:20:39

2.7 编程之美--最大公约数的3种解法[efficient method to solve gcd problem]的相关文章

求最大公约数的两种解法(欧几里得算法和素数分解)

最大公约数的两种解法(欧几里得算法和素数分解) 方法一: 欧几里得算法,又称辗转相除法 定理(欧几里得算法):设a和b是正整数,则存在最大求最大公因子d=(a,b)的一种算法,且存在求一组整数s,t使得d = sa+tb 举个例子:求168和60的最大公约数? 168 = 2 * 60 + 48 60  = 1 * 48 +12 48  = 4 * 12 由此得最大公约数为12 关于最大公倍数 C语言程序代码:很简单就不加注释了 #include<stdio.h> #define SWAP(a

编程之美---最大公约数

该文出自于编程之美中关于最大公约数问题一章. 任意给定两个数字,得到其最大公约数 GCD(greatest common divisor),如果两个数字都很大怎么解决. 分析:最大公约数早在公元前300年,欧几里得的<几何原本>里就提出了一个高效率算法---辗转相除法. 解法一: 假设f(x,y)表示x,y的最大公约数,取k=x/y,b=x%y,则x=ky+b,如果一个数字能同时整除x,y,那么必能够同时整除b,y:而能够同时整除b,y的数必能够同时整除x,y,即x,y的公约数与b,y的公约数

编程之美----最大公约数问题

求两个很大的数的最大公约数问题. 解法一:辗转相除法,但当数很大时,取模运算很耗时间. 解法二:利用f(x,y) = f(x-y, y)可以避免取模,但是当第一个数很大,而第二个数很小如1时,也比较耗时. 解法三:对于y和x来说,如果y=k*y1, x= k*x1,那么f(y,x)=k*f(y1,x1).如果x=p*x1,假设p是素数,并且y%p!=0,那么f(x,y)=f(p*x1,y)=f(x1,y).于是对于二进制表示的大整数而言可以每次除二了. 1 BigInt gcd(BigInt x

java并发编程--一道经典多线程题的2种解法

问题的描述 启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18,19,20....以此类推, 直到打印到75. 程序的输出结果应该为: 线程1: 1 线程1: 2 线程1: 3 线程1: 4 线程1: 5 线程2: 6 线程2: 7 线程2: 8 线程2: 9 线程2: 10 ... 线程3: 71 线程3: 72 线程3: 73 线程3: 74 线程3: 75

编程之美-分层遍历二叉树

问题:给定一个二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号.那么分层遍历如图的二叉树,正确的输出应该为: <span style="font-size:14px;">1 2 3 4 5 6 7 8</span> 书中还给出了问题2:打印二叉树中的某层次的节点(从左到右),其中根结点为第0层,成功返回true,失败返回false 分析与解法 关于二叉树的问题,由于其本身固有的

微软2014编程之美初赛第一场——题目3 : 活动中心

[来源] 题目3 : 活动中心 [分析] 本题採用的是三分法. 输入的一组点中找出左右边界.作为起始边界. while(右边界-左边界<精度){ 将左右边界构成的线段均匀分成3段,推断切割点的距离关系,抹去距离大的一段.更新左右边界. } 输出左(右)边界 [代码] #include <iostream> #include <vector> #include <cmath> #include <iomanip> using namespace std;

编程之美之2.7 最大公约数问题

问题: 求两个数的最大公约数 解法一: 欧几里得辗转相除法: f(x,y) = GCD(x,y), 取k = x / y, b = x % y,则:x = k*y + b; 如果一个数能整除x,y,则它也能整除b,y: 而且能整除b,y的数必能整除x,y,即x,y和b,y的公约数是相同的,其最大公约数也是相同的,即f(x,y) = f(y ,x % y) (x>=y>0) 例如,计算a = 1071和b = 462的最大公约数的过程如下:从1071中不断减去462直到小于462(可以减2次,即

读书问题之《编程之美》 -----12061161 赵梓皓

我阅读的书是<编程之美> 刚开始的时候阅读序,就觉得控制cpu利用率这个问题很好玩,所以重点看了这部分和解决办法,问题也都大部分是这部分的.那么问题就来了(挖掘机技术xxx?中国山东找蓝翔) 咳咳,问题在下面: 1.关于问题的提出.(也是一点点建议) 本书的主要内容是告诉读者如何思考问题和解决问题.但是提出问题也是很重要的,正如爱因斯坦所说“提出一个问题往往比解决一个问题更重要”,很多面试题(比如井盖为啥是圆的)我觉得正常人很少会想到.所以,这个问题是怎么想出来的...我很好奇.也希望作者能够

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明

先看看原题:<编程之美>3.6编程判断两个链表是否相交,原题假设两个链表不带环. 为了防止剧透使得没看过原题目的读者丧失思考的乐趣,我把最好的解法隐藏起来.由于这个问题本身的解答并不是本文的重点,扩展问题也采用这种形式呈现. 注:位于(*)符号之间的文字出自于:http://blog.csdn.net/v_july_v/article/details/6447013,作者v_JULY_v. 用指针p1.p2分别指向两个链表头,不断后移:最后到达各自表尾时,若p1==p2,那么两个链表必相交 用