不能直接用std::lcm是因为题目禁用内置函数,且C++17才引入该函数;需自行实现gcd(推荐abs+递归欧几里得),再用lcm(a,b)=abs(a)/gcd(a,b)*abs(b)先除后乘防溢出,并特判a或b为0时返回0。

为什么不能直接用 std::lcm?
因为题目明确要求不使用内置函数,而 C++17 起才提供 std::lcm(定义在 <numeric> 中),且它底层仍依赖 std::gcd。绕过内置函数意味着要自己实现最大公约数(GCD),再用公式 lcm(a, b) = abs(a * b) / gcd(a, b) —— 注意这里除法必须在乘法后做,否则可能溢出。
怎么安全算 GCD?推荐欧几里得递归写法
迭代或递归都行,但递归更简洁、不易错。关键点是:要用 abs 处理负数,终止条件是 b == 0,返回 a。
常见错误包括:
- 没处理
a或b为 0 的情况(lcm(a, 0)数学上无定义,实际中常约定为 0) - 用减法代替取模,效率极低(尤其两数差距大时)
- 忽略整数溢出:计算
a * b前不先除以gcd
示例 GCD 实现:
立即学习“C++免费学习笔记(深入)”;
int gcd(int a, int b) {
a = abs(a); b = abs(b);
return b == 0 ? a : gcd(b, a % b);
}LCM 计算时怎么避免 int 溢出?
直接写 abs(a) * abs(b) / gcd(a, b) 很危险——比如 a = 200000, b = 199999,乘积就超 int 范围。正确做法是先除后乘:
- 先算
abs(a) / gcd(a, b),再乘以abs(b) - 或者用
long long中转(如果输入范围允许) - 若必须用
int,优先选“先除后乘”,它能保证中间结果不溢出(因gcd整除a和b)
安全 LCM 示例:
int lcm(int a, int b) {
if (a == 0 || b == 0) return 0;
int g = gcd(a, b);
return abs(a) / g * abs(b); // 先除后乘,防溢出
}边界情况和实际调用要注意什么?
真实代码里容易漏掉这些细节:
-
a和b都为 0:按数学惯例lcm(0, 0)无定义,但很多场景返回 0 或抛异常,需明确约定 - 输入是负数:GCD 和 LCM 定义在正整数上,所以统一用
abs处理 - 编译器差异:C++11 及以后
abs对int安全,但若用long long,得配llabs - 性能敏感场景:如果反复调用,可考虑把
gcd改成迭代版避免栈溢出(不过对普通整数,递归深度最多约 log₂(min(a,b)),很安全)
真正难的不是公式,而是想清楚什么时候该用 abs、什么时候该检查 0、以及乘除顺序怎么安排才能既正确又不爆 int —— 这些地方一错,测试用例就过不了。


















