为什么此递归解决方案不起作用?

时间:2020-10-21 19:36:40

标签: javascript arrays algorithm recursion

问题如下:

编写一个名为productOfArray的函数,该函数接收一个数字数组并返回所有数字的乘积。

为什么此解决方案不起作用:

function productOfArray(arr){
    if (arr.length === 1) {
        return arr[0];
     }
     if (arr.length > 1){
     var last = arr.length - 1
     arr.pop()
     return arr[last] * productOfArray(arr)
}

有没有一种更好的方法可以在不更改数组的情况下递归地解决此问题?

3 个答案:

答案 0 :(得分:3)

arr[last]将为undefined,因为由于进行了pop调用,该索引处的数字不再存在。另外,pop将返回它删除的项目,因此您根本不需要索引,只需使用pop这样返回的内容:

var last = arr.pop();                   // remove the last number from the array and store it in the variable 'last'
return last * productOfArray(arr);      // use it here

答案 1 :(得分:2)

有没有更好的方法来递归地解决这个问题而无需更改数组?

老实说,递归并不是解决此问题的最佳方法。使用Array#reduce是处理此问题的惯用方式:

arr.reduce(
    (a, b) => a * b, // apply the operation
    1                // use the identity element for the operation
)                    //   which is the number 1 for multiplication

但是,由于您要在不修改数组的情况下进行递归操作,因此它是:

function productOfArray(arr) {
  if (arr.length === 0) { //terminal condition
    return 1;             // produce the identity element for multiplication
  }

  return arr[0] //first element
    *           //multiplied by
    productOfArray(arr.slice(1)) //the rest of the elements multiplied
}

const arr1 = [2, 3, 4];
const arr2 = [3, 3, 10];
const arr3 = [5, 3, 7];

console.log("2 * 3 * 4 =", productOfArray(arr1));
console.log("3 * 3 * 10 =", productOfArray(arr2));
console.log("5 * 3 * 7 =", productOfArray(arr3));

console.log("arr1 unchanged:", arr1);
console.log("arr2 unchanged:", arr2);
console.log("arr3 unchanged:", arr3);

使用Array#slice会创建一个新数组,因此初始数组不会受到影响:

const input = [2, 3, 4];
const result1 = input.slice(1);
const result2 = result1.slice(1);
const result3 = result2.slice(1);

console.log("result1:", result1);
console.log("result2:", result2);
console.log("result3:", result3);

并且由于我们以零个元素的数组结尾,因此我们在没有任何要乘的值之后退出。输入[2, 3, 4],递归将有效地评估2 * 3 * 4 * 1

注意:此实现确实表示productOfArray([])(空数组)产生1。这是否可接受可能会有所不同-这是一个不错的中性值。这样做的好处是您可以使用空数组来完成递归,否则,在最终条件为arr.length === 1的情况下,传递空数组将导致无限递归。除非另外处理:

if (arr.length === 0) {
  return 1; //or zero? Or whatever makes sense
}

if (arr.length === 1) {
  return arr[0];
}

但是,仅处理一个以上的条件基本上会使该函数的代码加倍。并假设无论如何都要返回1,这是不必要的代码。但是,如果您想将一个空数组的乘积视为零,那可能是值得的。

最后,可以使用destructuring of the function's parameter而不是.slice()来实现相同的逻辑

function productOfArray([head, ...tail]) {
  if (head === undefined) {
    return 1;
  }

  return head * productOfArray(tail);
}

const arr1 = [2, 3, 4];
const arr2 = [3, 3, 10];
const arr3 = [5, 3, 7];

console.log("2 * 3 * 4 =", productOfArray(arr1));
console.log("3 * 3 * 10 =", productOfArray(arr2));
console.log("5 * 3 * 7 =", productOfArray(arr3));

console.log("arr1 unchanged:", arr1);
console.log("arr2 unchanged:", arr2);
console.log("arr3 unchanged:", arr3);

Scott Sayuet指出in a comment,上述内容甚至可以简化为:

const prod = ([x, ...xs] = []) => 
    x == undefined ? 1 : x * prod (xs)

答案 2 :(得分:0)

您正在弹出,然后将其放置在某处。将其放入tmp变量中,然后相乘。

function productOfArray(arr) {
  if (arr.length === 1) {
    return arr[0];
  }
  if (arr.length > 1) {
    var last = arr.length - 1;
    var tmp = arr[last];
    arr.pop();
    return tmp * productOfArray(arr);
  }
}

console.log(productOfArray([2, 5, 1, 2]));