最大公约数
1.欧几里得算法——辗转相除法
公式为gcd(a,b) = gcd(b,a mod b)
例如要求50,30最大公因数,过程为
50%30=20,余数不为0 ,继续递归gcd(30,20)
30%20=10,余数不为0 ,继续递归gcd(20,10)
20%10=0,余数为0,停止,gcd(10,0)此时10即是最大公因数
2.一行代码即可求出最大公约数
int gcd(int a,int b){
return b==0? a:gcd(a%b);
}
求最小公倍数
int lcm(int a,int b){
return (long)a/gcd(a,b)*b;
}
3.证明过程
假设a,b是两个正整数,u是二者的公因子,并且a%b=r;
也就是我们要证明gcd(a,b)=gcd(b,r)
首先我们有a=k*b+r,k=0,1,2...
r=a-k*b,k=0,1,2...
并且我们知道a=s*u,b=t*u;代入可得
r=s*u-k*t*u=u*(s-kt);这说明u如果是a和b的公因子,那么u也是r的因子。
我们假设b和r的公因子为m,b=m*v,r=n*v;
a=k*m*v+n*v=v*(k*m+n);这说明m如果是b和r的因子,那么也是a的因子
因此我们得出结果,a和b的公因数集合=b和r的公因数集合。
4.时间复杂度
若a>b,时间复杂度大致为O(log a)的三次方.
5.经典习题
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
LeetCode878 第N个神奇数字
一个正整数如果能被 a
或 b
整除,那么它是神奇的。
给定三个整数 n
, a
, b
,返回第 n
个神奇的数字。因为答案可能很大,所以返回答案 对 10^9+ 7
取模后的值。
本题思路:利用二分搜索和容斥原理。
粗略定出第n个数字的范围为(1,n*a)。因为假设没有b的加入,那么第n个神奇的数字必然是n*a,但是由于有b加入,所以搜索范围会缩短。
我们假设有一个函数f(x)可以计算出从1到x一共有多少个神奇的数字,那么我们就可以利用二分答案法来计算出第n个神奇的数字在哪里。那么核心点就在于如何找到这个f(x)
f(x):在1-x范围上,能被a整除的有x/a这么多数字,能被b整除的有x/b这么多数字,有些数字既能被a又能被b整除,所以我们计算重复了,应该减去这一部分,也就是x/lcm(a,b)。这和离散数学里的容斥原理是一样的。
class Solution {
public int nthMagicalNumber(int n, int a, int b) {
long lcm=lcm(a,b);
long answer=0;
for(long l=0,r=(long)n*Math.min(a,b),m=0;l<=r;){
m=(l+r)/2;
if(m/a+m/b-m/lcm >=n){
r=m-1;
answer=m;
}
else{
l=m+1;
}
}
return (int)(answer%1000000007);
}
public long gcd(long a,long b){
return b==0?a:gcd(b,a%b);
}
public long lcm(long a,long b){
return (long)a*b/gcd(a,b);
}
}
6.Stein算法
7.裴蜀定理
同余原理
为什么要用同余原理
两个整数a、b,若它们除以整数m所得的余数相等,则称a与b对于模m同余或a同余于b模m。
记作:a≡b (mod m)。
如果两个整数是32位或者64位,那么进行各种运算时间复杂度是O(1),但如果是自己随机用字符串转换过来的k位整数,进行加减操作时间复杂度为O(k),乘除时间复杂度为O(k²)
如果我们想要提高运算速度,必须在中间过程取模运算,将时间复杂度控制到O(1)。
加法同余原理
(a + b) % m的值等于 ((a % m) + (b % m)) % m这个就是加法的同余原理。
乘法同余原理
(a * b) % m的值等于 ((a % m) * (b % m)) % m
减法同余原理
(a - b) % m的值等于 ((a % m) - (b % m) + m) % m,加上m可以保证一定不是负数,并且m%m=0不会影响最后结果。
比如说75和17,我们计算(75-17)%7=2; 75%7=5,17%7=3,answer=(5-3+7)%7。
再比如72,18,(72-18)%7=5 ; 72%7=2;18%7=4;answer=(2-4+7)%7.
以上便是同余原理,除法的同余原理一般用不到,会在后面逆元的知识里进行讲解。