【问题标题】:Return all subsets whose sum is a given value (subset sum problem)返回总和为给定值的所有子集(子集和问题)
【发布时间】:2019-05-08 14:34:38
【问题描述】:

子集总和问题是创建一个算法的问题,该算法接受一个数组和总和,并返回参数数组的所有子集,其总和等于给定总和。我正在尝试解决各种子集总和问题(使用 JavaScript),其中只允许非负整数,并且返回总和等于传入总和的所有子集。

我遵循动态编程方法来解决问题,并创建了一个函数,该函数返回一个二维布尔数组,该数组显示参数数组的哪些子集与参数相加。每行代表参数数组中的一个数字(第一行代表第一个元素,第二行代表第二个元素,以此类推);并且每一列代表一个sum的值(最左边的列代表sum = 0,最右边的列代表sum = "argument sum")。如果元素subsetArray[r][c] == true,则子集{array[0], array[1], ..., array[r]} 的元素总和为“c”。

const subsetSum = (array, sum) => {
   // Initialize empty 2D boolean array.
   let subsetArray = new Array(array.length)
      .fill(false)
      .map(() => new Array(sum + 1).fill(false));

   for (let e = 0; e < array.length; e++) {
      for (let s = 0; s <= sum; s++) {
         if (s === 0 || s === array[e]) {
            subsetArray[e][s] = true;
            continue;
         }
         if (e > 0) {
            if (
               subsetArray[e - 1][s] === true ||
               subsetArray[e - 1][s - array[e]] === true
            ) {
               subsetArray[e][s] = true;
            }
         }
      }
   }
   return subsetArray;
};

备注: 此功能不能解决问题。它只提供保证包含总和等于指定总和的子集的子集。

我的问题是我需要从这个布尔数组中提取总和等于指定总和的实际子集。我尝试过这样做,但我的方法中的逻辑(包括使用布尔数组来减少我必须分析的子集的数量)变得相当复杂,我很难实现它。

当一个人拥有subsetSum 生成的布尔数组时,有没有人知道找到总和等于给定总和的所有子集的好方法?

编辑 1

输入

Sum: 17
Array 7 2 1 5 1 20 7

输出

7 7 2 1

【问题讨论】:

  • 你有输入和想要输出的例子吗?
  • 我添加了一个输入/输出示例。

标签: javascript subset-sum


【解决方案1】:

您可以采用迭代和递归的方法来查找子集总和。

这种方法返回两个集合,因为有两个集合。

它的工作原理是从数组中取值与否。

函数的头部进行了各种检查,首先检查临时数组t中的所有元素是否达到总和。如果达到想要的总和,则将临时数组推送到结果集。

如果索引有数组长度的值,recursion停止。

最后一次检查向前看,如果总和小于或等于目标总和,则将实际索引 i 处的项目用于下一次递归。

fork 的最后一次调用省略了实际项目并继续下一个索引。

tl;dr

取一个元素,建立总和或省略元素。然后继续下一个索引。

取数示例:

7
7 2
7 2 1
7 2 1 5
7 2 1 5 1
7 2 1 5 1
7 2 1 5 1
7 2 1 5
7 2 1 5
7 2 1 5
7 2 1
7 2 1 1
7 2 1 1
7 2 1 1
7 2 1
7 2 1
7 2 1 7
7 2 1
7 2
7 2 5
7 2 5 1
7 2 5 1
7 2 5 1
7 2 5
7 2 5
7 2 5
7 2
7 2 1
7 2 1
7 2 1 7
7 2 1
7 2
7 2
7 2 7
7 2
7
7 1
7 1 5
7 1 5 1
7 1 5 1
7 1 5 1
7 1 5
7 1 5
7 1 5
7 1
7 1 1
7 1 1
7 1 1 7
7 1 1
7 1
7 1
7 1 7
7 1
7
7 5
7 5 1
7 5 1
7 5 1
7 5
7 5
7 5
7
7 1
7 1
7 1 7
7 1
7
7
7 7
7

2
2 1
2 1 5
2 1 5 1
2 1 5 1
2 1 5 1 7
2 1 5 1
2 1 5
2 1 5
2 1 5 7
2 1 5
2 1
2 1 1
2 1 1
2 1 1 7
2 1 1
2 1
2 1
2 1 7
2 1
2
2 5
2 5 1
2 5 1
2 5 1 7
2 5 1
2 5
2 5
2 5 7
2 5
2
2 1
2 1
2 1 7
2 1
2
2
2 7
2

1
1 5
1 5 1
1 5 1
1 5 1 7
1 5 1
1 5
1 5
1 5 7
1 5
1
1 1
1 1
1 1 7
1 1
1
1
1 7
1

5
5 1
5 1
5 1 7
5 1
5
5
5 7
5

1
1
1 7
1


7

function getSubsets(array, sum) {

    function fork(i = 0, s = 0, t = []) {
        if (s === sum) {
            result.push(t);
            return;
        }
        if (i === array.length) {
            return;
        }
        if (s + array[i] <= sum) { // shout circuit for positive numbers only
            fork(i + 1, s + array[i], t.concat(array[i]));
        }
        fork(i + 1, s, t);
    }

    var result = [];
    fork();
    return result;
}

console.log(getSubsets([7, 2, 1, 5, 1, 20, 7], 17));
.as-console-wrapper { max-height: 100% !important; top: 0; }

如果您愿意,您可以使用带有一个更多参数的生成器函数来生成临时结果集。

function* subsets(values, sum, parts = []) {
    var i, s;

    for (i = 0; i < values.length; i++) {
        s = sum - values[i];
        if (!s) {
            yield [...parts, values[i]];
        } else if (s > 0) {
            yield* subsets(values.slice(i + 1), s, [...parts, values[i]]);
        }
    }
}

console.log([...subsets([7, 2, 1, 5, 1, 20, 7], 17)]);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 我可以看到您的代码有效,但还没有完全理解它。您能否通过一个简单的示例来解释您的第一个代码 sn-p 的逻辑?
猜你喜欢
  • 2020-03-20
  • 2011-09-05
  • 1970-01-01
  • 2016-12-29
  • 2013-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多