前言

欧几里德算法作为有着非常简短的实现的算法,可能很多初学者(包括当时的我)都不求甚解。本文给出了GCD、LCM的性质,以及欧几里德算法的实现、证明和时间复杂度推导。

这里是我的个人网站:
https://endlesslethe.com/gcd-lcm-euclidean-algorithm.html
有更多总结分享,最新更新也只会发布在我的个人网站上。

什么是欧几里得算法

最大公约数问题是最早被研究的算法问题之一了,并且是ACM竞赛中能涉及到的很多数论内容,比如模线性方程,模线性方程组的基础。

欧几里得算法 (Euclidean algorithm) ,即大部分选手所知的“辗转相除法”,其核心在于不断将两数规模变小,最后实现对数时间内求解两个数的最大公约数。

其核心是:\[gcd(a,b) = gcd(b, a % b)\]

名词解释

  1. 最大公约数:即最大公因子,能够同时整除a和b的最大因子,记作gcd(a, b),或gcd
  2. 最小公倍数:能够被a和b整除的最小数,记作lcm(a, b),或lcm。
  3. %:指的是取余运算(取模运算),用例: a % b
  4. |:指的是整除运算,a | b表明a可以整除b,即a是b的因子

GCD和LCM的一些性质

  1. a, b都能分解为有限个素数的积
  2. gcd(a, b)中只含a,b的全部公共素因子
  3. lcm(a, b)中含有a,b的所有素因子
  4. \(gcd%lcm=0\)
  5. \(gcd * lcm = a * b\)
  6. \(lcm/gcd = a/gcd * b/gcd\)
  7. \(gcd(ka, kb) = k * gcd(a, b)\)
  8. \(lcm(ka, kb) = k * lcm(a, b)\)
  9. \(lcm(\frac{a}{b},\frac{c}{d})=\frac{lcm(a,c)}{gcd(b,d)}\)

简单证明

这里只证明第六个性质:\[gcd * lcm = a * b\]
根据\(a / gcd\) 和 \(b / gcd\) 这两个数互质,且两者包含a、b的非公共素因子
故\[lcm = gcd * (a / gcd) * (b / gcd)\\
lcm = (a * b) / gcd\]
所以\(a*b = gcd * lcm\)

Note:我们习惯写为lcm = a / gcd * b,以此来避免溢出。而且通常使用变形后的等式性质七。

直观理解欧几里德算法

我们不妨设\(a = m * gcd\), \(b = n * gcd\)
那么通过恒等式\(gcd(a,b) = gcd(b, a % b)\),a将减少若干个b即(n*gcd)到\(a % b * gcd\)
交换后\(a = n * gcd, b = a % b * gcd\)

因为每次交换都会减少很多个gcd,无疑是很快的(后面会证明,至少是对数的)

欧几里德算法实现

等式\(gcd(a,b) = gcd(b, a % b)\)可以理解为一个数减小,再两个数交换。
因为两个数的值经过循环不断变小,在结束循环前,两个数不可能小于0,且不可能同时为0。
所以最后b先变为0,且有
\[gcd(a_n,b_n)=\cdots=gcd(a_{n−1},b_{n−1})=gcd(a_0,0)\\
a_0 = gcd(a, b)
\]

递归版

ll gcd(ll a, ll b) {return !b ? a : gcd(b, a%b);
}

迭代版

ll gcd(ll a, ll b) {while (b != 0) {ll res = a % b;a = b;b = res;}return a;
}

证明gcd(a,b) = gcd(b, a % b)

\[
我们为了简化,默认a>b:\\
设gcd(a,b)=d,gcd(b,a-bx)=e,\\
∵d|a,d|b\\
∴d|a-bx\\
∴d|gcd(b,a-bx),即d|e\\
∵e|b,e|a-bx\\
∴e|bx+(a-bx),即e|a\\
∴e|gcd(a,b),即e|d\\
∴d=e\\
证毕。
\]

斐波那切数列和GCD

斐波那契数列有这样一条性质:
\[gcd(F_n,F_m)=F_{gcd(n,m)}\]

证明见参考文献VII“斐波那契数列与gcd之间一个有趣的定理”

时间复杂度

最差时间复杂度

这里给结论:欧几里得算法最差的情况下就是斐波那契数列相邻的两项
即:\[F_{s} \leq a \leq F_{s+1}\]
a为两个数中较大的,s为最大操作次数(最坏时间复杂度),F为斐波那契数列。

平均时间复杂度

给结论:\(s = (12 * \ln 2 * \ln N) / π ^ 2 + 1.47\) (N为其中较小的那个数)

不过上面的结论需要大量的数学推导,我们不妨根据斐波那切数列的通项公式来理解:
则s的增长速度是对数,时间复杂度是对数的

证明

我给出一个自己的证明,其他证明可以见参考文献:
\[
为了方便理解递推关系式,设一共会辗转n次,a_n=a, b_n=b\\
即gcd(a_n,b_n)=\cdots=gcd(a_{n−1},b_{n−1})=gcd(a_0,0)\\
因为有gcd(a_n,b_n) = gcd(b_n, a_n % b_n) = gcd(a_{n-1}, b_{n-1})\\
存在关系a_{n-1}=b_n,a_n=t * b_n+b_{n-1}\\
不妨推广为a_{k-1}=b_k,a_k=t * b_k+b_{k-1}\\
将a_k、b_k用a_{k-1}、b_{k-1}表示\\
得到递推式:ak=tb_k+b_{k-1}=ta_{k-1}+a_{k-2}\\b_k=a_{k-1}
\]

为了让an和bn尽量小(达到最坏时间复杂度),我们应该让t=1:\[a_k=a_{k-1}+a_{k-2}\\b_k=a_{k-1}\]

第0次 第1次 第2次 第3次 第4次 第n次
a gcd gcd 2*gcd 3*gcd 5*gcd Fn*gcd
b 0 gcd gcd 2*gcd 3*gcd Fn-1*gcd

故对于\(a=F_n * gcd,b=F_{n-1} * gcd\),欧几里德算法会达到最坏的复杂度。

题目总结

  • Uva 11388
    只需要利用性质六即可

  • HIT OJ 2010 GCD & LCM Inverse
    可以根据性质六+暴力枚举通过HIT OJ,但不能通过POJ 2429,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <math.h>
using namespace std;typedef long long ll;ll gcd(ll a, ll b) {return !b ? a : gcd(b, a%b);
}int main() {ll x, y;while (cin >> x >> y) {ll t = y / x;for (ll i = sqrt(t); i > 0; i--) {if (t % i == 0) {if (gcd(t / i, i) == 1) {cout << i * x << " " << y / i << endl;break;}}}    }return 0;
}
  • Zoj 1577 GCD & LCM
    需要素因子分解,暴力分解可过

  • POJ 2429 GCD & LCM Inverse
    将HIT OJ 2010暴力枚举修改为素因子分解,然后暴力计算最接近sqrt(lcm/gcd)的组合,即可通过POJ。

  • POJ 3101
    可以根据相对速度,也可以根据公式\(\frac{x}{a}%\frac{1}{2}=\frac{x}{b}%\frac{1}{2}=\frac{x}{c}%\frac{1}{2}\)
    化简一下都是同一个东西,然后根据分数的gcd公式。需要高精度。

参考文献

I. 欧几里得算法原理
II. 关于lcm,gcd的一些性质
III. ACM数论之旅3—最大公约数gcd和最小公倍数lcm(苦海无边,回头是岸( ̄∀ ̄))
IV. 欧几里得算法证明
V. 数论学习小记 其之三 Gcd与Lcm
VI. 【POJ3101】Astronomy——分子的最小公倍数
VII. 斐波那契数列与gcd之间一个有趣的定理
VIII. gcd常见结论及gcd与斐波那契结合–hdu6363.
IX. 辗转相除法求最大公约数(gcd)的斐波那契数列(fib)最坏时间复杂度的证明
X. 欧几里得算法(即辗转相除法)的时间复杂度
XI. 欧几里得算法时间复杂度简单分析

浅析欧几里德算法 GCD和LCM相关推荐

  1. 集训笔记---扩展欧几里德算法(POJ NO.1061 青蛙的约会 有点烦人小跳蛙gcd)

    又在搬砖,本来以为这是一个追及问题,后来发现数据好像并不是那么个意思,后来把方程列出来,经过一个去模的操作,我们其实可以找到一点线索,那就是,一个经过变形的二元一次方程,那么在这种情况下,就可以利用扩 ...

  2. Java实例15 - 求最大公约数 gcd 辗转相除 欧几里德算法

    /** * 辗转相除法求最大公约数又叫欧几里德算法 * 它的依据是公理gcd(n,m) = (m, n%m) */ package al; public class Gcd { public stat ...

  3. 【备战蓝桥】JavaB组算法小讲解——GCD和LCM

    大家好,这里是祁十一!今天为大家整理了一下GCD和LCM的内容. 目录 一.GCD(最大公约数) 1.定义 2.性质 3.代码实现 <1>Java自带函数 <2>辗转相除法 二 ...

  4. 离散数学/初等数论:用“质因子分解法”和“欧几里得算法”求最大公约数gcd;“质因子分解法”和“最简算法”求最小公倍数lcm;以及对“意义”的一些看法。

    需要在开头提前说明,本篇文章仅仅用于在学习初等数论或者离散数学时候对算术基本定理的理解,实际应用的时候把结论告诉大家,想求最大公约数就用欧几里得算法是最简单的,在本篇不再赘述,有机会我会在其他文章中说 ...

  5. 数论----gcd和lcm

    gcd即最大公约数,lcm即最小公倍数. 首先给出a×b=gcd×lcm 证明:令gcd(a,b)=k,a=xk,b=yk,则a×b=x*y*k*k,而lcm=x*y*k,所以a*b=gcd*lcm. ...

  6. Bailian2793 孙子问题【扩展欧几里德算法+中国剩余定理】

    2793:孙子问题 总时间限制: 15000ms 内存限制: 65536kB 描述 我国古代<孙子算经>中,记有如下算题:"今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩 ...

  7. 欧几里德算法 扩展欧几里德算法

    欧几里德算法 欧几里德算法又称辗转相除法,是指用于计算两个正整数a,b的最大公约数. 计算公式:gcd(a,b) = gcd(b,a mod b). 算法实现: public static int g ...

  8. 欧几里德算法(辗转相除法)

    欧几里德算法又称为辗转相除法,用于计算两个非负整数的最大公约数. template<typename T> T gcd(const T &a, const T &b) {r ...

  9. 数论(一)——素数,GCD,LCM

    这是一个数论系列:) 一.素数 ×费马小定理 Theorem: 设 p 是一个素数,a 是一个整数且不是 p 的倍数,那么 很遗憾,费马小定理的逆定理是不成立的.对 a = 2,满足的非素数 n 是存 ...

最新文章

  1. 微软CEO致雅虎董事会的最后通牒信
  2. Android之解析XML
  3. 南通一酒店搞了个“虎景房”,这睡得着?
  4. 【PAT乙级】1026 程序运行时间 (15 分)
  5. 牛客题霸 两数之和C++题解/答案
  6. ORACLE 查询所有用户调度作业
  7. 人之间的尊重是相互的_人与人之间的感情,最基本的是相互尊重
  8. 小米回应“米家”商标争议;人人 App 回归社交市场;TiDB 2.1.19 发布| 极客头条...
  9. 将apache的htaccess转换为nginx的重写规则
  10. 程序员52个堪称神器的学习网站,每天坚持一小时,让你受益一生
  11. 空手套白狼之——兼职中介
  12. ElementUI(1):很好的前端开发框架
  13. android mysql 驱动_Java-使用com.mysql.jdbc.Driver的Android MySQL
  14. Indexes: RDBMS vs Coherence vs Lucene
  15. 日常生活中常用的五星级句子
  16. 张乐:研发效能的黄金三角及需求与敏捷协作领域的实践
  17. echarts柱状图如何从纵向改为横向
  18. 中国皮肤病药物市场评估与投资方向研究报告(2022版)
  19. Arduino-IRremote-红外遥控器,发射与接收
  20. Python写爱心闪光动图

热门文章

  1. 企业微信H5网页费用报销操作界面 Vue
  2. 博客升级_原水_新浪博客
  3. 理财U24 认股权证、可转债、可赎债 习题解读
  4. Java--Lambda
  5. c语言贪吃蛇游戏的论文,基于c语言的贪吃蛇游戏论文.doc
  6. 被跟卖了怎么投诉?亚马逊邮箱官方邮件联系方式汇总
  7. 抗菌药物临床应用总结
  8. 自主开发的app,通过打包的apk安装到seuic扫描仪上,扫描灯无法调起,但是直连调试却能成功的解决方法(Android studio)
  9. SSRS地图图例嵌入自定义图像显示解决
  10. goland navigate back and forward