数论基础 gcd与lcm

最大公因数gcd与最小公倍数lcm

  1. 第一步当然要说一说定义啦

定义:找到一个最大的数g,使得g|a,g|b,则g=gcd(a,b)

找到一个最小的数l,使得a|l,b|l,则l=lcm(a,b)

注:“g|a”表示g整除a

  1. 众所周知,最大公因数与最小公倍数有一个常用结论

即 gcd(a,b) * lcm(a,b)=a * b

那么它是怎么来的呢(思考两分钟)

下面让我们来简易证明一下:

证明:设最大公因数为g,最小公倍数为l;

由定义可知g|a && g|b;

即 a,b均可写作 a=g * a1,b=g * b1

那么gcd(a1,b1)=1-->why? (感性理解一下:如果这两个数的最大公约数不等于1的话,那么gcd(a,b)它一定不等于g,而为gcd(a1,b1) * g。也就是说如果g为a,b的gcd,那么gcd(a1,b1)一定等于1)

由lcm的定义可知 l=a * a2=b * b2;

由已证可知 l=g * a1 * a2=g * b1 * b2;

我们单独拿出g * a1 * a2=g * b1 * b2这一部分;

两边同时约去g可得到 a1 * a2=b1 * b2;

且易知只有a2=b1;b2=a1时此式成立,且l尽量小

再将此结论带入得

l=g * a1 * b1;

又因为gcd(a,b)=g

所以gcd(a,b) * lcm(a,b)=g^2 * a1 * b1=g * a1 * g * b1=a * b;

证毕;

所以,以后凡是有任何问题让求两个数的最小公倍数的时候,在已知gcd(a,b)的情况下,可以转为lcm(a,b)=(a * b)/gcd(a,b);

那么接下来当然就要说一下gcd(a,b)到底怎么求

介绍一种常用的方法

辗转相除法(欧几里得算法)

gcd(a,b)=gcd(b,a-b);(假设a>b)

应用多次(假设应用n次)得到gcd(a,b)=gcd(b-a-n * b)

即可以得到:

gcd(a,b)=gcd(b,a%b);(相当于多次减法一起应用)

约定 gcd(a,0)=gcd(0,a)=a;

附上代码

int gcd(int a,int b)

{

if(b==0) return a;

else return gcd(b,a%b);

}

那么计算gcd(a,b)的复杂度是多少

由上可知我们的计算过程是gcd(a,b)=gcd(b,a%b)

假设a>b 那么a%b一定小于a/2;

如果b<=a/2 又因为a%b<b即小于a/2;

如果b>a/2 那么a%b=a-b(因为此处商只能是1) 因为a-b<a/2,所以a%b<a/2;

所以无论b取什么值,a%b始终小于a/2;

换句话说,我们的每一次操作,都会使较大数变成较大数原来的一半以下

所以最多做log n次操作

即计算gcd(a,b)的复杂度是log n的

思考计算gcd(a1,a2,a3,...,an)的复杂度是多少呢

n log n?其实并不是的

显而易见,当我们算出gcd(a1,a2)=g,之后再次求gcd的话,是用g与a3求出新gcd的值,即gcd(g,a3).因此在算g与a3的最大公因数时,因为你的最大公因数是会越来越小的,因此,得到的复杂度并不是log a3,而是log g.

因此,计算gcd(a1,a2,a3,...,an)的复杂度应该是O(n+log n).

在这里,第一个n表示要枚举a1到an;

Log n代表的需要将每一个最大公因数不断地折半,最后来得到结果。

最后补充一点:如要求lcm(a,b,c),我们先要将其转换成lcm[lcm(a,b),c]再进行求解;

注意:lcm(a,b,c)≠(a*b*c)/(g^2);

 

上一篇:算法竞赛专题解析(20):数论--GCD和LCM


下一篇:LeetCode 1201. 丑数 III(最小公倍数+二分查找)