为什么这个递归解决方案不起作用



问题如下:

编写一个名为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)
}

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

有没有更好的方法可以在不改变数组的情况下递归解决这个问题?

老实说,递归并不是最好的方法。使用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。这是否可以接受可能会有所不同——这是一个不错的中性值。好处是do可以用空数组完成递归,否则在arr.length === 1的终端条件下,传递空数组将导致无限递归。除非将其作为另一种情况处理:

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

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

最后,可以使用函数参数的析构函数来实现相同的逻辑,而不是使用.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在评论中指出的那样,上述内容甚至可以缩短为:

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

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

在将其放在某个位置之前,您正在弹出。将其放入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]));

最新更新