【问题标题】:Specific Method of Summing n Number of Array values Together With Recursion (Javascript Algorithm)将n个数组值与递归相加的具体方法(Javascript算法)
【发布时间】:2020-05-03 16:15:15
【问题描述】:

这是问题

编写一个递归函数 sum(arr, n),它返回数组 arr 的前 n 个元素的和。

我在互联网上发现的尝试

  function multiply(arr, n) {
    if (n <= 0) {
      return 1;
    } else {
      return multiply(arr, n - 1) + arr[n - 1];
    }
  }

我的问题

1. else 语句是如何工作的?

我无法理解我们要添加 arr[n - 1] 的内容。

2.有没有更简单的方法来编写这段代码?

【问题讨论】:

  • 1.) 基本上这就是递归的工作原理。我们将 arr[n - 1] 添加到下一次调用 (n-2) 的结果中,依此类推,直到达到 index = 0。此递归从数组中的最大索引元素到最低索引元素进行。 2.)这已经是通过递归实现这一目标的一种非常简单的方法。如果要总结元素,则需要以某种形式使用此语句 return multiply(arr, n - 1) + arr[n - 1];(递归调用 + 当前调用)。
  • 但我很确定代码不会返回正确的总和。因此,我将添加一个提供正确代码的答案。
  • 这很有帮助,但是因为公式只返回 1,else 语句的第一部分如何提供任何有用的内容以添加到 arr[n-1]。例如。如果 arr 是:[1, 2, 3, 4] 并且 n 是 3,则返回 multiply(arr, n - 1) 在循环的前两个循环中代表什么
  • 我更新了我的答案。请检查这是否现在回答了 n=3 和数组 [1,2,3,4] 的特定情况

标签: javascript algorithm recursion


【解决方案1】:

首先,该功能不正确。我不能真正告诉你它想要做什么,但它肯定不会添加数组的前 n 个元素。那么我们如何写一个呢?什么是递归?

递归并不是作为一种编程思想开始的,它是从数学开始的,就像许多其他编程结构一样。所以在我们写 sum 函数之前,让我们在数学上定义它:

f(arr, 0) = 0
f(arr, n) = f(n - 1) + arr[n - 1]

我知道数组在数学中不是这样使用的,但到底是什么,这仍然很有用。应该注意的第一件事是有两个定义,而不是一个。第一个定义说:数组arr的前0个元素之和永远为0。无论之前或之后发生什么,永远为0。

第二个定义说,要对数组 arr 的前 n 个元素求和,我们必须找到前面元素的和,然后简单地添加 arr[n - 1]另一种思考方式,前 n 个元素的总和,就是前 n - 1 个元素加上第 n 个元素的总和。这可能会导致头痛,不,它会导致头痛。因此,为了减轻您的痛苦,我们将逐步了解它。

假设我通过函数f([1, 2, 3, 4], 2),我应该得到 3。这是函数计算结果为 3 的方式:

f([1, 2, 3, 4], 2) = f([1, 2, 3, 4], 1) + [1, 2, 3, 4][1]
f([1, 2, 3, 4], 1) = f([1, 2, 3, 4], 0) + [1, 2, 3, 4][0]
f([1, 2, 3, 4], 0) = 0

我们完成了。什么?我们完了?我们肯定是。请注意我们如何定义我们所做的每个函数调用?这意味着我们可以向后工作,并用定义替换每个函数调用。所以:

f([1, 2, 3, 4], 0) = 0
f([1, 2, 3, 4], 1) = 0 + 1 = 1
f([1, 2, 3, 4], 2) = 1 + 2 = 3

只需写出定义,我们就可以评估答案。考虑起来可能很棘手,但评估它并没有变得更简单,这就是为什么对递归函数有很多赞誉的原因。不管怎样,我们已经在数学上定义了它,我们现在可以很容易地用 JavaScript 或任何你选择的语言来实现它——只要它支持递归。

function sum(arr, n)
{
    if (n <= 0) return 0; // f(arr, 0) = 0
    return sum(arr, n - 1) + arr[n - 1]; // f(arr, n) = f(arr, n - 1) + arr[n - 1]
}

有几点需要注意。如果函数不返回某些内容,则不能进行递归,因为对函数的求值依赖于替换。并且每个递归函数都需要至少有两个定义,这样循环才能结束。此外,您看到代码如何几乎与数学定义一对一匹配?我知道,这真的很棒。

编辑:if (n == 0) 很好,但如果 n 为负数则不起作用。所以,我把它换成了n &lt;= 0

【讨论】:

  • 通过数学解释的好方法。也很喜欢你的写作风格:P。
  • 谢谢!我发现以“数学”方式调试递归函数通常非常有用,所以我想我会做同样的解释。
  • 你们太棒了!
【解决方案2】:

我已经在 cmets 中回答了这个问题。据我了解,您发布的代码不会返回正确的结果。它应该是这样的:

  function multiply(arr, n) {
    if (n <= 0) { // return 0 if count is 0 or negative
      return 0;
    } else { // sum up the next n - 1 elements with the current element
      return multiply(arr, n - 1) + arr[n - 1];
    }
  }

实际上n=0 的结果应该是 0 而不是 1,同样当添加任意数组时,return 1 会得到错误的结果。应该是return 0。例如。 [5,4,3,2] = 14(旧版本 15)。

正如我现在回答的那样,我还将在下面附上我的评论:

1.) 基本上这就是递归的工作原理。我们将 arr[n - 1] 添加到下一次调用 (n-2) 的结果中,依此类推,直到达到 index = 0。此递归从数组中的最大索引元素到最低索引元素进行。

2.) 这已经是一种通过递归实现这一目标的非常简单的方法。如果你想总结元素,你需要这个语句:return multiply(arr, n - 1) + arr[n - 1]; in some form(递归调用+当前元素)。

更新 cmets 中的问题:

var arr = [1,2,3,4], n = 3;

  1. 调用:multiply(arr, n-1)(value=0 plus 1 plus 2) + arr[n-1](value=3)
  2. 呼叫:multiply(arr, n-2)(value=0 plus 1) + arr[n-2](value=2)
  3. 致电:multiply(arr, n-3)(value=0) + arr[n-3](value=1)
  4. 调用:因 0(值=0)而终止

现在换个角度想一想。直到递归终止,什么都没有总结出来。而且在 4. call 中也没有求和,因为我们没有进入 else 分支。

因此,计算的第一个总和将是:

0(n-4) + 1(n-3).

这将被返回,下一个计算将是:

(0(n-4) + 1(n-3)) + 2(n-2).

最后计算的总和也是最终结果:

(0(n-4) + 1(n-3) + 2(n-2)) + 3(n-1).

每个递归都需要两件事:

  1. 递归调用
  2. 终止条件

【讨论】:

  • 您能否提供一个示例来说明 multiply(arr, n - 1) 将代表什么。例如。如果 arr 是 [1, 2, 3, 4] 并且 n 是 3
  • 因为它让我感到困惑,您可以将任何内容添加到数组和数字作为两个单独的参数。
  • @AndrewNeedsHelp 我在答案中添加了附加信息,我认为这应该有助于理解。我会在几分钟后回复这个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-16
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
相关资源
最近更新 更多