首页 > 解决方案 > For 循环影响递归变量

问题描述

我正在尝试使用递归来创建一个函数,该函数可以从帕斯卡三角形内的任何序列中获取任何项。基本上使用自然数作为第一组的加法序列,然后使用每个前一组作为加法序列,始终从 1 开始。

我目前正在学习 JavaScript,并且正在做我已经知道的 Python 工作来测试 JavaScript 中的一些基本原理。然而 for 循环似乎总是跳过一些数字。我相信正在发生的是,当函数调用自身并再次运行 for 循环时,它会影响更高一级的函数中的变量 I ,导致它跳过序列中的一个数字。我不知道如何避免这种情况,因为 JavaScript 允许变量在同一范围内的函数中使用,这是有道理的,但我不知道如何避免这种情况。

 var simplex = function(s,t){
  if (s == 1){
    return t
  } else{
    var n=1;
    for (i = 1; i<t; i++){
      n += simplex(s-1,t+1);
    }
    return n
  }

}

console.log(simplex(3,3))

标签: javascriptfor-looprecursionscope

解决方案


其他人指出了未声明变量的相当简单的问题。

但即使在修复之后,仍然存在三个逻辑错误。您没有在循环i内使用循环变量。虽然有时这没问题,但它不在这里。您需要它作为simplex. 其次,你的循环边界停止了。您想要t上一列的条目,但您通过 testing 停止与t - 1st的条目i < t。最后,您从 开始您的累积 ( n) 1。总和应该从 开始累加0。修复这些,我们有一个看起来像这样的工作函数:

const simplex = function(s, t) {
  if (s == 1) {
    return t
  } else {
    var n = 0;
    for (let i = 1; i <= t; i++){
      n += simplex(s - 1, i)
    }
    return n
  }
}

添加一些日志语句来显示流程,我们可以得到:

const simplex = function (s, t, d = 0) {
  console.log('|   '.repeat(d) + `simplex (${s}, ${t})`)
  if (s == 1) {
    console.log('|   '.repeat(d) + `\`+-> ${t}`)
    return t
  } else {
    var n = 0;
    for (let i = 1; i <= t; i++){
      n += simplex (s - 1, i, d + 1)
    }
    console.log('|   '.repeat(d) + `\`+-> ${n}`)
    return n
  }

}

simplex (3, 3) //=> 10
.as-console-wrapper {max-height: 100% !important; top: 0}

simplex (3, 3)
|   simplex (2, 1)
|   |   simplex (1, 1)
|   |   `+-> 1
|   `+-> 1
|   simplex (2, 2)
|   |   simplex (1, 1)
|   |   `+-> 1
|   |   simplex (1, 2)
|   |   `+-> 2
|   `+-> 3
|   simplex (2, 3)
|   |   simplex (1, 1)
|   |   `+-> 1
|   |   simplex (1, 2)
|   |   `+-> 2
|   |   simplex (1, 3)
|   |   `+-> 3
|   `+-> 6
`+-> 10

但我相信这个功能可以在很多方面进行简化。有一些简单的事情,比如将else块移到根目录,并使用箭头函数代替函数表达式。对我来说更重要的是使用一个辅助函数,比如sum汇总多个值,而不是在这个函数中包含那个逻辑。通过还包括countTo简单地返回第一个n计数数字的 ,我们可以使用map,使代码更具声明性。所以我可能更喜欢这样的版本:

const countTo = (n) => n < 1 ? [] : [...countTo (n - 1), n]
const sum = (xs) => xs .reduce ((a, b) => a + b, 0)

const simplex = (s) => (t) =>
  s == 1
    ? t
    : sum (countTo (t) .map (simplex (s - 1)))

console .log (simplex (3) (3))

此版本还对 API 进行了一项更改。这个函数不是采用单纯形数和项并返回值,而是采用单纯形数并返回一个接受项并返回值的函数。这意味着将其称为 likesimplex (s) (t)而不是simplex (s, t). 做到这一点并不难,而且有很多好处。但是将其转换为另一种格式很容易,只为实现增加了非常小的复杂性。


更新

我忘了提到我的第一种方法,即将单纯形数视为直接进入帕斯卡三角形的索引。帕斯卡三角形包含二项式系数,可以使用简单的递归计算choose (n, k) = choose (n, k - 1) + choose (n - 1, k - 1),并带有一些简单的基本情况。

使用它,simplex (s, t)只是choose (s + t - 1, t). 它可能看起来像这样:

const choose = (n, k) =>
  k == 0
    ? 1
  : n == 0
    ? 0
  : choose (n - 1, k) + choose (n - 1, k - 1)

// Ex: choose (7, 3) //=> 35

console .log ('Pascal Triangle:\n');
console .log (
  Array .from (
    {length: 9}, 
    (_, n) => Array .from ({length: n + 1}, (_, r) => choose (n, r))
  ).map (
    r => r .map (n => `${n}`.padStart(2, ' ')) .join (' ')
  ) .join ('\n') + '\n ...'
)

const simplex = (s, t) => 
  choose (s + t - 1, t)
  
console.log ('simplex (3, 3): ', simplex (3, 3))
.as-console-wrapper {max-height: 100% !important; top: 0}


推荐阅读