双层循环中反复调用gcd性能差,应排序剪枝或改用单次遍历求全局gcd;lcm易溢出,需用long、先除后乘并加溢出检查。

双层循环里反复调用 gcd 会拖慢性能
Java 标准库没有内置 gcd,很多人自己写个两数 gcd 函数后,直接在双层循环里对每对数字都算一遍——比如求一个数组中所有数对的最大公约数最大值。这看似直觉,但时间复杂度是 O(n² × log(min(a,b))),n=10⁴ 就可能超时。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 先用
Arrays.sort()降序排列,最大公约数往往出现在大数之间,可提前break或剪枝 - 若目标是“整个数组的最大公约数”,根本不用双层循环——单次遍历调用
gcd(gcd(gcd(a[0],a[1]),a[2]),...)即可 - 避免在循环内重复创建对象或装箱,比如用
int而非Integer做参数
lcm 容易溢出,尤其和双层循环叠加时
最小公倍数公式是 a * b / gcd(a, b),但 a * b 在 int 范围内就极易溢出(比如两个接近 10⁵ 的数相乘就超 2³¹)。双层循环一跑,第一批结果就可能是负数或 0,后续 gcd 全乱套。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 改用
long计算lcm,且先除后乘:(a / gcd(a, b)) * (long) b - 如果业务允许近似或限定范围,加一层溢出检查:
if (a > Integer.MAX_VALUE / b * gcd(a,b)) { /* 跳过或报错 */ } - 不要在双层循环里无条件存所有
lcm到集合——内存爆得比 CPU 快
嵌套循环变量命名和边界容易写反
写 for (int i = 0; i 是常规操作,但实际手写时,j 从 0 开始、i 和 j 次序颠倒、漏掉 <code>+1 导致重复计算同一对,非常常见。更隐蔽的是:当数组含 0 时,gcd(a, 0) 应返回 abs(a),但自制函数若没处理,会进死循环或抛异常。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 循环变量统一用
i、j,别用m/n或idx1/idx2——增加认知负担 - 边界检查写成
j 或 <code>j == i立刻能发现逻辑错误 -
gcd函数开头加if (b == 0) return Math.abs(a);,别依赖递归自动收敛
双层循环本身不是问题,问题在于把数学定义直接硬套成代码结构。真正难的不是嵌套几层,而是想清楚:你要的到底是“某一对”的极值,还是“全体”的合成值——后者根本不需要双层。










