You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

是否可在不使用递归与while循环的前提下重写递归函数findNum?

可以!用数学公式直接重写,无需递归或循环

首先先把原递归函数的代码贴出来,方便我们拆解逻辑:

function findNum(a, b) { 
  if (!b) { b = 0; } 
  if (a < 2) { throw new Error('wrong'); } 
  if (a === 2) { return 1 / a + b; } 
  return findNum(a - 1, b + 1 / (a * (a -1))); 
}

拆解原函数的递归本质

原函数的核心逻辑是通过递归累加一个数列:每次递归时,会把1/(a*(a-1))加到参数b中,直到a递减到2,最后返回1/2 + b。如果把这个累加过程展开(假设初始b=0),实际计算的是:
1/(n*(n-1)) + 1/((n-1)*(n-2)) + ... + 1/(3*2) + 1/2

用裂项相消化简级数

这里可以用到分式裂项的数学技巧:1/(k*(k-1)) = 1/(k-1) - 1/k。把每一项拆开来后,累加的中间项会相互抵消:

  • 1/(3*2) = 1/2 - 1/3
  • 1/(4*3) = 1/3 - 1/4
  • ...
  • 1/(n*(n-1)) = 1/(n-1) - 1/n

把这些项加起来,中间的-1/3+1/3-1/4+1/4都会抵消,最后剩下1/2 - 1/n。再加上原函数最后返回的1/2,总和就是:
(1/2 - 1/n) + 1/2 = 1 - 1/n

如果初始传入了非0的b,那最终结果就是b + 1 - 1/a(因为b会被一直累加进去)。

重写后的无递归/无循环函数

基于上面的推导,我们可以直接写出简化版的函数,完全不需要递归或循环:

function findNum(a, b) {
  // 保留原函数的b参数默认值处理
  const initialB = b ?? 0;
  // 保留原函数的错误校验逻辑
  if (a < 2) {
    throw new Error('wrong');
  }
  // 直接用化简后的公式计算
  return initialB + 1 - 1 / a;
}

验证正确性

举几个例子验证和原函数结果一致:

  • 调用findNum(2):返回1 - 1/2 = 0.5,和原函数返回1/2 + 0完全一致;
  • 调用findNum(3):返回1 - 1/3 ≈ 0.6667,原函数递归计算为1/(3*2) + 1/2 = 1/6 + 1/2 = 2/3,结果一致;
  • 调用findNum(4, 2):返回2 + 1 - 1/4 = 2.75,原函数递归计算为2 + 1/(4*3) + 1/(3*2) + 1/2 = 2 + 1/12 + 1/6 + 1/2 = 2.75,结果完全匹配。

内容的提问来源于stack exchange,提问作者Adope Adopish

火山引擎 最新活动