使用递归计算LCM时出现无限输出,该场景是否适合采用递归实现?
LCM递归实现方案及和循环实现的对比
原有代码的核心问题
你写的版本中每次递归是将当前的num1、num2直接翻倍,而非累加两数的初始值,也没有保留初始值作为参数,因此两数永远不会相等,只会无限递归直到栈溢出,自然跑不出你注释中的预期结果。
完全可以用递归实现LCM,主流有两种实现思路
思路1:基于你原本的步进逻辑修正
核心是新增参数保留两数的初始值,每次让较小的数累加对应初始值,直到两数相等:
const leastCommonMultiple = (a, b, originA = a, originB = b) => { if (a === b) return a return a < b ? leastCommonMultiple(a + originA, b, originA, originB) : leastCommonMultiple(a, b + originB, originA, originB) } // 测试验证 console.log(leastCommonMultiple(4, 6)); // 12 console.log(leastCommonMultiple(3, 5)); // 15 console.log(leastCommonMultiple(2, 10)); // 10
该版本可正常跑出预期结果,但缺点也很明显:如果输入两个互质的大整数,递归深度会非常高,极易触发栈溢出。
思路2:基于GCD(最大公约数)实现,性能更优
根据数学公式 LCM(a,b) = |a*b| / GCD(a,b),我们可以先递归实现GCD的欧几里得算法,再推导LCM,该方案递归深度极低,完全不存在栈溢出风险:
// 递归实现欧几里得算法求最大公约数 const gcd = (a, b) => b === 0 ? a : gcd(b, a % b) // 基于GCD求最小公倍数 const leastCommonMultiple = (a, b) => Math.abs(a * b) / gcd(a, b)
该方案是工业界的通用实现,性能远高于暴力步进方案。
递归和循环的选择建议
- 若使用基于GCD的实现:递归写法更简洁易读,递归深度最多为
log₂(min(a,b)),即便是10位以上的大整数,递归深度也不会超过40,完全不需要担心栈溢出问题,用递归完全合适。 - 若使用暴力步进类的实现:递归存在栈溢出风险,这种场景更适合用循环实现,更推荐直接替换为GCD方案。
内容的提问来源于stack exchange,提问作者Aeton
相关产品推荐
相关产品推荐

