一文讲清计算质因数分解,最大公约数,最小公倍数的方法
一文讲清计算质因数分解,最大公约数,最小公倍数的方法
Sarzn质因数、最大公约数与最小公倍数:原理与C++实现
尔辈需究物理
一、核心原理剖析
1.1 质因数:
定义:把一个正整数分解为若干个质数相乘的形式,这些质数就是该数的质因数。 简单来说,质因数就是构成一个数的“最小质数单元”。
示例: 21 = 3 × 7(3和7是21的质因数) 60 = 2 × 2 × 3 × 5(2、3、5是60的质因数) 90 = 2 × 3 × 3 × 5(2、3、5是90的质因数)
1.2 最大公约数(GCD):两数的“最大公共除数”
先理清基础概念,再看核心定义:
- 约数:能整除某数的正整数(如6的约数是1、2、3、6,注意:1是所有正整数的约数);
- 公约数:能同时整除两个(或多个)数的正整数(如6和12的公约数是1、2、3、6);
- 最大公约数:公约数中数值最大的那个数(如6和12的最大公约数是6,而非原内容中的12)。
核心特征:两个数的最大公约数,是它们所有公共质因数的乘积。 > 示例:6(2×3)和12(2×2×3)的公共质因数是2和3,因此GCD(6,12)=2×3=6。
1.3 最小公倍数(LCM):两数的“最小公共倍数”
定义:能被两个(或多个)数同时整除的最小正整数。
核心公式(仅适用于两个数): 对于正整数a和b,满足:
a × b = GCD(a, b) × LCM(a, b)
由此可推导出最小公倍数的计算方法:
示例:计算6和12的最小公倍数 GCD(6,12)=6,因此LCM(6,12)=(6×12)/6=12。
二、实践落地:C++代码实现
2.1 质因数分解
功能说明
将一个正整数分解为质因数相乘的形式,处理边界条件(如输入为1),并优化循环性能。
优化后代码
1 |
|
代码说明
- 边界处理:新增非正整数、输入为1的判断,避免程序异常;
- 性能优化:循环仅遍历到
sqrt(num),因为一个数的质因数不会超过其平方根; - 输出优化:用
isFirstFactor控制乘号,避免出现“12 = × 2 × 2 × 3”这类错误格式; - 复用性:将分解逻辑封装为函数,便于后续调用。
运行示例
1 | 输入:90 |
2.2 最大公约数(GCD):辗转相除法
辗转相除法(欧几里得算法)是计算GCD的最优方法,核心逻辑:GCD(a,b) = GCD(b, a%b),直到余数为0,此时的除数即为最大公约数。
迭代版,无栈溢出风险
1 |
|
递归版(简洁,但大数可能导致栈溢出)
1 |
|
运行示例
1 | 输入:6 12 |
2.3 最小公倍数(LCM):基于GCD的计算
优化后代码
1 |
|
代码说明
- 溢出优化:将
a*b/gcd(a,b)改为(a/gcd(a,b))*b,避免两个大数相乘导致的整数溢出; - 边界处理:新增输入为0的判断,因为0没有公倍数;
- 依赖复用:直接复用已实现的GCD函数,符合“代码复用”最佳实践。
运行示例
1 | 输入:6 12 |
三、实战练习:洛谷题目(U652633)
https://www.luogu.com.cn/problem/U652633
结合上述知识点,可完成洛谷题目U652633(质因数分解),以下是适配题目的优化代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using namespace std;
int main() {
int num, original_num;
cin >> num;
original_num = num;
// 题目核心边界:输入1时直接输出1
if (num == 1) {
cout << 1 << endl;
return 0;
}
bool firstFactor = true;
// 优化循环:i*i <= num,减少遍历次数
for (int i = 2; i * i <= num; i++) {
while (num % i == 0) {
if (!firstFactor) {
cout << "×"; // 题目要求的乘号格式
}
cout << i;
num /= i;
firstFactor = false;
}
}
// 处理剩余的质数
if (num > 1) {
if (!firstFactor) {
cout << "×";
}
cout << num;
}
cout << endl;
return 0;
}
事项
- 性能优化:质因数分解时,循环到
sqrt(num)而非num,时间复杂度从O(n)降至O(√n); - 边界条件:务必处理输入为1、0、负数的情况,避免程序逻辑错误;
- 溢出问题:计算LCM时,优先做除法再乘法,避免整数溢出(如
(a/gcd)*b而非a*b/gcd)。





