Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
697 views
in Technique[技术] by (71.8m points)

javascript - Return all subsets whose sum is a given value (subset sum problem)

The subset sum problem is the problem to create an algorithm that takes an array and sum and returns all subsets of the argument array whose sum is equal to the given sum. I am attempting to solve a variety of the subset sum problem (using JavaScript) in which only non-negative integers are allowed and where all the subsets whose sum is equal to the passed in sum are returned.

I have followed a dynamic programming approach to solving the problem and have created a function that returns a two-dimensional boolean array that shows which subsets of the argument array that sum to the argument some. Each row represents a number in the argument array (the first row represents the first element, the second row represents the second element, etc.); and each column represents a value of sum (the leftmost column represents sum = 0 and the rightmost column represents sum = "argument sum"). If the element subsetArray[r][c] == true, then the subset {array[0], array[1], ..., array[r]} has elements that sum to "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;
};

Remark: This function does not solve the problem. It only provides the subsets that are guaranteed to include subsets whose sum is equal to the specified sum.

My problem is that I need to extract the actual subsets whose sum is equal to the specified sum from this boolean array. I have tried to do this, but the logic in my approach (which involves using the boolean array to reduce the number of subsets that I have to analyze) becomes rather complicated and I am having difficulty implementing it.

Does anyone know a good way of finding all subsets whose sum is equal to the given sum when one has the boolean array generated by subsetSum?

Edit 1

Input

Sum: 17
Array 7 2 1 5 1 20 7

Output

7 7 2 1
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could take an iterative and recursive approach for finding subset sums.

This approach returns two sets, because of the double ones.

It works by taking values form the array or not.

Int he head of the function various checks are made, the first checks if the sum is reached by all element in the temporary array t. If the wanted sum is reached, the temporary array is pushed to the result set.

If the index has the value of the length of the array, the recusrion stops.

The last check looks ahead and if the sum is smaller or equal to the target sum, the the item at the actual index i is taken for the next recursion.

The last call of fork omits the actual item and goes on with the next index.

tl;dr

Take either an element, build the sum or omit the element. Then go on with the next index.

An example of taken numbers:

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; }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...