javascript - 如何将这个递归变成尾递归?

标签 javascript algorithm recursion tail-recursion

对于始终大于 0 的唯一数字的给定数组,我需要找到这些数字的所有可能的唯一组合,这些数字在求和时等于某个数字。

例如,getNumberComponents([7, 4, 3, 2, 5, 6, 8, 1], 8) 应返回

[ [ 7, 1 ], [ 4, 3, 1 ], [ 3, 5 ], [ 2, 5, 1 ], [ 2, 6 ], [ 8 ] ] 因为每个子数组中所有数字的总和等于8

我的解决方案:

function getNumberComponents(numArray, number) {
    const arrayLength = numArray.length;
    const allVariants = [];

    function findComponents(currentIndex = 0, currentVariant = []) {
        while (currentIndex < arrayLength) {
            const currentElement = numArray[currentIndex];

            const currentSum = currentVariant.reduce((acc, cur) => acc + cur, 0);

            const sumWithCurrent = currentSum + currentElement;

            if (sumWithCurrent === number) {
        allVariants.push([...currentVariant, currentElement]);
            }

            currentIndex++;

            if (sumWithCurrent < number) {
                findComponents(currentIndex, [...currentVariant, currentElement]);
            }
        }
    }
    
    findComponents();
    
    return allVariants;
}

但我想知道是否可以使用尾递归?我不知道如何将我的解决方案变成尾递归。

最佳答案

要使此尾部递归,您可以:

  • 跟踪为得出当前总和而选择的所有指数。这样您就可以轻松地将选定索引替换为后继索引。

  • 在函数的每次执行中,获取“下一个”索引组合。这可以按如下方式完成:

    • 如果尚未达到总和,则在最近选择的索引之后添加紧随其后的索引,并调整总和
    • 如果总和已达到或超过,则删除最近选择的索引,然后添加后继索引,并调整总和
    • 如果没有后继索引,则忽略该索引并替换列表中的前一个索引,再次调整总和
    • 如果索引列表中没有更多条目,则一切都已完成。
  • 除了累加总和之外,您还可以减少传递给递归的数字——保存一个变量。

  • 使函数返回包含所有变体的数组,因此不需要内部函数,也不需要跟随函数调用的任何操作。

这是一个实现:

function getNumberComponents(numArray, number, selectedIndices=[], allVariants=[]) {
    let i = selectedIndices.at(-1)??-1;
    if (number < 0) { // Sum is too large. There's no use to adding more
        i = numArray.length; // Force the while-condition to be true
    } else if (number == 0) { // Bingo
        allVariants.push(selectedIndices.map(idx => numArray[idx]));
    }
    while (++i >= numArray.length) { // No more successor index available
        if (selectedIndices.length == 0) return allVariants; // All done
        i = selectedIndices.pop(); // Undo a previous selection
        number += numArray[i]; // Remove from sum
    }
    selectedIndices.push(i); // Select index and recur:
    return getNumberComponents(numArray, number - numArray[i], selectedIndices, allVariants);
}

console.log(getNumberComponents([7, 4, 3, 2, 5, 6, 8, 1], 8));

关于javascript - 如何将这个递归变成尾递归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75095879/

相关文章:

Python无限递归打印所有子项

java - foob​​ar 僵尸感染挑战

php - 类别树的递归 php mysql 查询/函数

javascript - GraphQL中如何获取peer字段?

javascript - 具体组合算法

javascript - PHP 中的 Node.js console.time() 等效吗?

c# - 道格拉斯-普克算法 : understanding use with polgyons

构造函数中的Java随机方法不起作用

javascript - 在父 div 上使用 .height() 后,改变高度的子元素不再影响父元素的高度,为什么?

javascript - 如何使用 Node.js 将 docx 文件打印到打印机