博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
最大公约数问题
阅读量:6525 次
发布时间:2019-06-24

本文共 2331 字,大约阅读时间需要 7 分钟。

解法一

早在公元前300年,欧几里德就在《几何原本》中给出了高效的辗转相除法。欧几里得辗转相除法是现在算法的鼻祖。

算法思路(伪代码)

function gcd (a, b)    while  b ≠ 0        t  = b        b = a mod b  //取余        a = t     return a

算法证明

1. 两个数a、b,用a除以b,得 a = bq + r(q是商   r是余数)。若 r等于0,则b为最大公约数,否则,接着往下走

2. 证明一点:任何a和b的公约数都是r的公约数。

   证明:假设d为a、b的公约数,则a = md  b = nd.  

            r = a - bq = md - ndb = (m - nb)d. 得证

3. 对于所有的d,这都是正确的,因此a、b的公约数也即b、r的公约数。a、b的最大公约数也即b、r的最大公约数。

这样一直重复2 3过程,直到r=0。则b、r的最大公约数为b。这样得求。

例子说明

12 和 8的最大公约数:

b != 0 a = 12, b = 8tmp = b = 8b = a % b = 12 % 8 = 4a = tmp = 8 b != 0tmp = b = 4b = a % b = 0a = tmp = 4最大公约数为4

程序实现

 迭代思路

#include 
int gcd(int a, int b){ int tmp; while (b != 0) { tmp = b; b = a % b; a = tmp; } return a;}int main(){ printf("%d\n", gcd(12, 8)); return 0;}

 

 递归思路

#include 
int gcd(int a, int b){ return (!y) ? x : gcd(b, a % b);}int main(){ printf("%d\n", gcd(12, 8)); return 0;}

瑕疵:用到了取模运算,对于大整数而言,取模运算是非常昂贵的开销,成为了该算法的瓶颈。

 

解法二

类似于欧几里德辗转相除法,两个数的公约数必然是两者之差的公约数(a = md, b = nd, a - b = (m-n)*d),因此f(a,b) = f(b, a-b),这里注意前者大于后者,否则,把两者换过来。

示例

f(42,30)=f(30,12)=f(12,18)=f(18,12)=f(12,6)=f(6,6)=f(6,0), 结果为6

代码

#include 
using namespace std;int gcd(int m, int n){ if(n == 0) return m; if(m < n) return gcd(n, m); else return gcd(n, m-n);}int main(){ cout << "42, 30:" << gcd(42, 30) << endl; return 0;}

结果

瑕疵:该方法免去了大整数除法的繁琐,但是新的不足之处在于:遇到一大一小,相差悬殊的情况(例如:(200000000, 1))

 

解法三

分析公约数特点:对于x和y来说(k为素数)

如果x = k * x1, y = k * y1,那么gcd(x,y)=gcd(x1,y1)*k

如果x = k * x1, y不能被k整除,那么gcd(x,y)=gcd(x1,y)

如果x不能被k整除 y = k * y1,那么gcd(x,y)=gcd(x,y1)

代码

#include 
using namespace std;int gcd(int m, int n){ cout << "m, n:" << m << " " << n << endl; if(n == 0) return m; if(m < n) return gcd(n, m); else { if(m % 2 == 0) { if(n % 2 == 0) return (gcd(m >> 1, n >> 1) << 2); else return gcd(m >> 1, n); } else { if(n % 2 == 0) return gcd(m , n >> 1); else return gcd(n, m - n); } }}int main(){ cout << "20000, 1000:" << gcd(20000, 1000) << endl; return 0;}

结果

评述:解法一瓶颈在于计算大整数除法,解法二瓶颈在于有时迭代次数太多。解法三充分综合了一二的优点。另外解法三选取2作为素数,通过移位方便的进行乘除,避免了一定的大整数乘除法。

 

参考:《编程之美》2.7

转载地址:http://hujbo.baihongyu.com/

你可能感兴趣的文章
前端总结·基础篇·JS(三)arguments、callee、call、apply、bind及函数封装和构造函数...
查看>>
[Ramda] Get Deeply Nested Properties Safely with Ramda's path and pathOr Functions
查看>>
[LeetCode] Convert BST to Greater Tree 将二叉搜索树BST转为较大树
查看>>
spring AspectJ切入点语法详解 记录以便查阅
查看>>
二叉树进阶之搜索二叉树的判断与找出搜索二叉树中出错的结点
查看>>
Hessian矩阵【转】
查看>>
OAuth 2和JWT - 如何设计安全的API?
查看>>
使用ShellExecute打开目标文件所在文件夹并选中目标文件
查看>>
日期和时间处理的类库
查看>>
《WCF技术剖析(卷1)》(修订版)目录
查看>>
从零开始学.net多线程系列(三)——同步
查看>>
TypeError: __init__() got an unexpected keyword argument ‘maxlength’
查看>>
C#语法中一个问号(?)和两个问号(??)的运算符是什么意思?
查看>>
如何用DOS命令删除文件夹
查看>>
分享一个帮助你在线测试响应式设计的web工具 - Screenqueri.es
查看>>
基于Ext.Panel编写一个图片列表类
查看>>
Android利用V4包中的SwipeRefreshLayout实现上拉加载
查看>>
HTML5树叶飘落动画
查看>>
SQL Server系统数据库备份最佳实践
查看>>
你真的会玩SQL吗?和平大使 内连接、外连接
查看>>