如何计算总和等于给定值的所有数字数组元素组合?

时间:2019-11-08 11:03:44

标签: javascript arrays

问题在标题中。
例如:

鉴于此array = [1,1,2,2,3,7,9,1]sum = 7,我希望得到以下结果:

1,1,2,2,1
1,1,2,3
...
7

一个二次时间的答案是微不足道的,我正在寻找一个次二次时间的解决方案...
我目前的解决方案:

function subsetSum(numbers, target, partial) {
  var s, n, remaining;

  partial = partial || [];

  // sum partial
  s = partial.reduce(function (a, b) {
    return a + b;
  }, 0);

  // check if the partial sum is equals to target
  if (s === target) {
    console.log(partial.join(","))
  }

  if (s >= target) {
    return; // if we reach the number we don't bother to continue
  }

  for (var i = 0; i < numbers.length; i++) {
    n = numbers[i];
    remaining = numbers.slice(i + 1);
    subsetSum(remaining, target, partial.concat([n]));
  }
}

subsetSum([1,1,2,2,3,7,9,1], 7);

输出:

1,1,2,2,1
1,1,2,3
1,1,2,3
1,2,3,1
1,2,3,1
1,2,3,1
1,2,3,1
2,2,3
7

对于2k个1位数的数字,在处理4分钟后,我的盒子中的nodejs(v11.14.0)吐出了:

致命错误:接近堆限制的无效标记紧凑分配失败-JavaScript堆内存不足

:-(

1 个答案:

答案 0 :(得分:4)

您可以通过避免使用内置的数组方法(迭代和最昂贵的切片)进行递归调用,并采用递归函数,该函数获取要获取的下一个数字的索引,收集的值的数组和新的目标,而无需最后一次获取的值。

此方法返回所有可能的值,这些值不是唯一的,取决于给定的数据。这种方法仅适用于正数。

function subsetSum(numbers, target) {
    function iter(index, right, delta) {
        if (!delta) return result.push(right);
        if (index >= numbers.length) return;
        if (delta - numbers[index] >= 0)
            iter(index + 1, [...right, numbers[index]], delta - numbers[index]);
        iter(index + 1, right, delta);
    }
    var result = [];
    iter(0, [], target);
    return result;
}

subsetSum([1, 1, 2, 2, 3, 7, 9, 1], 7).map(a => console.log(...a));
.as-console-wrapper { max-height: 100% !important; top: 0; }