你在刷题时是否遇到过超时困惑?明明测试样例通过却总卡在TLE(超时错误)?本文通过最大公约数(GCD)这一经典问题,带你用暴力枚举法直击算法效率瓶颈,再用欧几里得算法实现千倍性能飞跃。文末附赠LeetCode实战优化技巧,助你彻底掌握从理论到落地的完整优化链路!
目录
一、问题定义与应用场景
1. 什么是最大公约数
-
数学定义:两个整数的最大公共因数(能同时整除两个整数的最大正整数)
-
示例:12和18的公约数为1,2,3,6 → GCD=6,表示为 gcd(12,18)=6
-
应用场景:
分数化简(3/9 → 1/3)
密码学(RSA算法基础)
图形学(屏幕宽高比适配)
二、求解方法
方法一:枚举-暴力求解
1.算法思路:
逆向遍历法:首先找两数中的较小值,从两数较小值开始递减遍历,找到首个能同时整除的因子
算法思路图解:
int main()
{
int x, y;
scanf("%d %d", &x, &y);
int min = x < y ? x : y;//找到最小值
//倒序遍历
for (int i = min; i > 0; i--)
{
if ((x % i == 0) && (y % i == 0))
{
printf("%d", i);
break;
}
}
return 0;
}
2.复杂度分析
-
时间复杂度:O(min(a,b))
-
空间复杂度:O(1)
-
适合场景:小数据量(数值<1e4)
方法二:辗转相除法(欧几里得算法)
1.数学原理证明
定理:gcd(a,b) = gcd(b, a mod b)
递归推导:gcd(48, 18) = gcd(18, 12)
= gcd(12, 6)
= gcd(6, 0)
= 6
int main()
{
int m, n;
scanf("%d %d", &m, &n);
int k = 0;
while (k = m % n) //当余数为0时终止
{
m = n;
n = k;
}
printf("%d", n);
return 0;
}
说明:要求 m 和 n 的最大公约数,就让 m % n,若余数 k 不为0,就把 n 的值赋给 m ,k 的值赋给 n ,以此类推,直到余数为 0 ,最后 n 就是要找的最大公约数
2.复杂度对比
算法 | 平均时间复杂度 | 最坏情况 |
---|---|---|
暴力枚举 | O(n) | O(n) |
辗转相除法 | O(log n) | O(log n) |
为什么辗转相除法更高效?
数学解释:每次迭代至少减少一半数值(斐波那契数列衰减)