👑一、约数和因数的区别
约数必须在整除的前提下才存在,而因数是从乘积的角度来提出的。如果数与数相乘的积是数,是的因数。
1.约数只能对在整数范围内而言,而因数就不限于整数的范围。
举个栗子:。2和8是16的因数,也可以是16的约数。
另外一个栗子:,虽然可以说0.9X8是7.2的因数,却不能说0.9和8是7.2的约数。
2.对于一个整数,凡能整除它的数,都是这个整数的约数。而因数只有在多个数字相乘等于n的时候,才能说
举个栗子:1、2、4、8、16都能整除16,因此,1、2、4、8、16也都是16的约数。
而当一个数被分解成两个或几个数相乘时,因数的个数就受到了限定。
另外一个栗子:。只能说2和8是16的因数,而不能说1、2、4、8、16都是16的因数,因为的结果,并不等于16。
👑二、求最大公约数(gcd)
最大公约数(Greatest Common Divisor)指两个或多个整数共有约数中最大的一个,一般称之为"gcd",是其英文单词小写的首字母缩写。
a, b的最大公约数记为gcd(a, b), 其中需要满足{}的条件。
a=16 b=12
↓
分解a的约数集合:{1, 2, 4, 8, 16};
↓
分解b的约数集合:{1, 2, 3, 4, 6, 12};
↓
找到最大的公共约数,也就是①都存在于a和b约数集合中的②最大数字。
↓
最大公约数->4
求最大公约数有多种方法,常见的有 质因数分解法、 短除法、 辗转相除法、 更相减损法。短除法如下图所示,它常常用于手算,面对程序题常见的大数无能为力,所以不过多介绍。
“质因数分解法”和“更相减损法”速度较慢,且本文旨在精简,所以代码写一套最优秀的坤坤便可以了。所以咱们着重讲解“辗转相除法”,也就是广为人知的“欧几里得算法”。
欧几里得算法的演化🎈
用gcd(a,b)表示a和b的最大公因数:有结论gcd(a,b)=gcd(a,ka+b)。
要证明这个原理很容易:如果p是a和ka+b的公约数,p整除a,也能整除ka+b.那么就必定要整除b,所以p又是a和b的公约数,从而证明他们的最大公约数也是相等的。推理如下
if gcd(a, ka+b) = p
↓
由于p是a的约数,那么 a % p == 0 , ka+b % p == 0
↓
当且仅当 ka % p == 0 并且 b % p == 0 的时候 (ka + b) % p 才成立
↓
所以{ka + b % p == 0}、{ka % p == 0 }、{b % p == 0}
基于上面的原理,就能实现我们的迭代相减法:
gcd(36,14)=gcd(2*14 + 8,14)=gcd(8, 14)=gcd(8, 8+6)=gcd(8, 6)=gcd(6+2, 6)=gcd(2, 6)=gcd(2, 3X2+0) = gcd(2, 0)
,而gcd(2,0)的最大公约数是2。
0是所有整数的约数,因此 0 和任何整数的最大公约数都是这个整数本身。
写代码🎈
那么如何使用C++代码实现欧几里得算法呢?
//input
a(int), b(int)
//algorithm
//和推理不一样的是,我们需要一直保持 a > b, 为了方便,取余的操作固定是a%b,所以需要保持a>b
if b < a:
temp = b
b = a
a = temp
//我们可以看到当b为0的时候我们才结束了推理,所以b=0是循环的终止条件
while b:
//现在a > b了 先得到余数
c = a % b
//让a = b, b = 余数,完美的交换的同时保持 a>b
a = b
b = c
//ouput
//最后b=0 a=最大公约数
gcd(a,b)->a
请同学们自行实现一下,之后可以对照一下下面的参考代码。
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int T;
cin >> T;
while(T--)
{
int a, b;
cin >> a >> b;
//a % b == 0, 则b就是最大公约数,可以提前结束循环。
while(a % b)
{
int c = a % b;
a = b;
b = c;
}
cout << b << endl;
}
}
大家学到这里一定非常幸苦,如果每次遇到gcd的题目,大家都要写这么多代码肯定很麻烦,接下来我们学习递归的方法。
#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int a, int b){ // 一般要求a>=0, b>0。若a=b=0,代码也正确,返回0
return b? gcd(b, a%b):a;
}
int main(){
int a , b;
cin >> a >> b;
cout<<gcd(a,b)<<endl;
return 0;
}
哇,核心代码居然一共才写了三行
① int gcd(int a, int b){ // 一般要求a>=0, b>0。若a=b=0,代码也正确,返回0
② return b? gcd(b, a%b):a;
}
③ cout<<gcd(a,b)<<endl;
那么如何理解呢,这是一个三目运算符,如果b≠0,就返回gcd(b, a%b),如果b=0,就返回a。
举个例子:
gcd(16, 12),进入下一层递归->gcd(12, 4),进入下一层递归 -> gcd(4, 0),返回上一层递归a=4->gcd(12,4),返回a=4->gcd(16, 12),返回a=4。所以最终结果就是4。是不是很神奇很奇妙呢?
大家学到这里幸苦啦,但其实大家都白学了,这是因为👇
白学了🎈
#include<iostream>
#include<algorithm> //这个头文件内置了一个求最大公约数的函数__gcd(a,b)
using namespace std;
int main(){
int a, b;
cin>> a >> b;
cout<<__gcd(a,b)<<endl; //直接调用就写完了,核心代码就这一行,一行更比三行短。
return 0;
}
👑三、求最小公倍数
记公式
然后就做完了
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int a,b;
cin>>a>>b;
cout<<a*b/__gcd(a,b)<<endl;
return 0;
}