【问题标题】:Javascript function to determine if number any combination of numbers in array add up to max valueJavascript函数确定数组中数字的任意组合是否等于最大值
【发布时间】:2015-12-24 20:06:19
【问题描述】:

例如:如果 arr 包含 [4, 6, 23, 10, 1, 3],则输出应返回 true,因为 4 + 6 + 10 + 3 = 23。数组不会为空,不会包含所有相同的元素,并且可能包含负数。
我的尝试
使用递归方法查找 arr 的所有排列并将元素相加以查看它们是否加起来为数组最大值。该函数正确检查所有排列,但不返回正确的布尔值。

function arrayAddition(arr) {
    var arrMax = arr.sort(function(a, b) {
                     return a - b;
                 }).pop();

    function recArrAdd(sub, arr) {

        if (arr.length > 0) {
            var arrSum = sub.concat(arr[0]).reduce(function(prev, curr) {
                return prev + curr;
            });

            if (arrSum === arrMax) return true;
            recArrAdd(sub.concat(arr[0]), arr.slice(1));
            recArrAdd(sub, arr.slice(1));
        }
        return false;
    }

    return recArrAdd([], arr);
}

console.log(arrayAddition([1, 2, 3]));

【问题讨论】:

  • @maioman 在发布的函数中有一个.reduce() 调用!
  • 值有什么限制吗?
  • 你能检查一下这个链接吗。。类似的问题codereview.stackexchange.com/questions/36214/…
  • 这是一个相关的问题,@SanketBajoria,我在那里添加了答案。

标签: javascript arrays algorithm


【解决方案1】:

我认为问题在于if (arrSum === arrMax) return true; 检查。在程序执行的某些时刻arrSum实际上等于各自的arr[0]。但是当 arr[0] 恰好是数组中的 MAX 元素时,您会得到误报。

所以,你必须合并另一个检查:if (arr[0] != arrMax)

此外,当if (arr.length > 0) 检查失败时,您的函数不应返回 false。相反,您可以使用全局标志变量(found,如下面的代码所示)并将其作为最终结果返回。


编辑:此外,出于性能原因,检查 if (found) return true; 位于 recArrAdd() 的顶部:它有助于避免不必要的进一步调用,因为当 foundtrue 时工作完成。

例如,没有它,recArrAdd()被调用255次,187(输入[1,3,5,4,25,8,14])。


以下是您修改后的代码和一些示例输出:

function arrayAddition(arr) {
    var arrMax = Math.max.apply(Math, arr);
    var found = false;


    function recArrAdd(sub, arr) {
        if (found) return true;
        if (arr.length > 0) {
            var arrSum = sub.concat(arr[0]).reduce(function(prev, curr) { return prev + curr;});
            if (arrSum === arrMax){
                if (arr[0] != arrMax){
                    found = true;
                    return found;
                }
            };
            recArrAdd(sub.concat(arr[0]), arr.slice(1));
            recArrAdd(sub, arr.slice(1));
        }
        return found;
    }

    return recArrAdd([], arr);
}

console.log("[1,2,3] -> "+arrayAddition([1,2,3]));
console.log("[1,2,5] -> "+arrayAddition([1,2,5]));
console.log("[1,2,5,4,20,8] -> "+arrayAddition([1,2,5,4,20,8]));
console.log("[1,2,5,4,21,8] -> "+arrayAddition([1,2,5,4,21,8]));
console.log("[1,3,5,4,25,8,14] -> "+arrayAddition([1,3,5,4,25,8,14]));
console.log("[1,3,5,4,45,8,14] -> "+arrayAddition([1,3,5,4,45,8,14]));

产生:

在 Firefox 中使用 Firebug。

【讨论】:

    【解决方案2】:

    你在寻找这样的东西吗?:

    function sumEqualsMax(values) {
        var maxValue = Math.max.apply(Math, values);
        var sumParts = values.slice();
        sumParts.splice(sumParts.indexOf(maxValue), 1);
    
        var sumValue = sumParts.reduce(function (previousValue, currentValue) {
            return previousValue + currentValue;
        }, 0);
    
        return sumValue === maxValue;
    }
    
    var values = [4, 6, 23, 10, 3];
    console.log(sumEqualsMax(values));
    

    【讨论】:

    • 当某些值的组合(不一定是全部)加起来达到最大值时,它应该返回true
    • 啊,我明白了。没有从您的问题中得到答案。
    【解决方案3】:

    如果您的数字以 31 为界,则存在漂亮的解决方案:

    n 为最大值,arr 为其余数字。然后下面的代码检查你想要什么

    var mask = 1;
    for (var idx = 0; idx < arr.size; idx++) {
        mask = mask | mask << arr[idx];
    }
    return (mask >>> n) & 1;
    

    可以使用boolean 的数组而不是位掩码来推广更大的限制。

    一些解释。开头的掩码是00000001,表示通过空集的总和我们可以得到0(因为1在位置0)。然后在每一步mask 是我们可以做出的所有总和的掩码。然后通过为每个和s 添加arr[idx],我们可以得到s + arr[idx]。所以新总和的掩码将是mask &lt;&lt; arr[idx]。但是我们仍然可以制作所有旧的掩码mask。所以掩码的新值是mask | mask &lt;&lt; arr[idx]。最后,mask 是所有可能和的掩码,如果 n 是可能的和,则第 n 位 ((mask &gt;&gt;&gt; n) &amp; 1) 是10

    【讨论】:

    • 你能详细解释一下吗?这些是 >>>
    • 不要使用for ... in 循环遍历数组。
    猜你喜欢
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-27
    • 2021-01-16
    相关资源
    最近更新 更多