 GFG App
Open App Browser
Continue

# Minimum Subset sum difference problem with Subset partitioning

Given a set of N integers with up to 40 elements, the task is to partition the set into two subsets of equal size (or the closest possible), such that the difference between the sums of the subsets is minimized. If the size of the set is odd, one subset will have one more element than the other. If the size is even, both subsets will have the same size. After finding the minimum difference, output the subsets.

Examples:

Input: arr[] = {45, 34, 4, 12, 5, 2}
Output: Min Difference 0 Subset 1 : {34, 12,  5} Subset 2 : {45,  4,  2}
Explanation: The above generated two subsets have sum
∑ Subset 1 : 34+12+5 =  51
∑ Subset 2 : 45+4+2 =  51
The minimum difference is abs( ∑ S1 – ∑ S2 ) = 0, which is the minimum difference possible.

Input: arr[] = {3, 34, 4, 12, 5, 2 }
Output: Min Difference 18 Subset 1 : {3  34  2} Subset 2 : {4  12  5 }
Explanation: The above generated two subsets have sum
∑ Subset 1 : 3+34+2 =  39
∑ Subset 2 : 4+12+5 =  21
The minimum difference is abs( ∑ S1 – ∑ S2 ) = 18, which is the minimum difference possible.

Approach: To solve the problem follow the below idea:

The idea is to partition the array into two different subsets and then generate the subsets.

Below are the steps for the above approach:

• Partition the array arr into two equal parts, if n is odd, one element is extra in either of the subsets. Make a custom structure that stores the generated subset indices and their sum. For each part, generate the subsets indices and store their (sum, subset) against the number of elements in the subset. That is, arr[ ni ] ={ sum, subset } where ni is the number of elements in the subset. For convenience, assign part1 the extra element in case of an odd size of the array.
• Sort the sums in the vector part2, so we can binary search later on this.
• The objective is to create subset1. Subset2 can be obtained by removing all elements of subset1 from arr. Subset1 will contain n/2 elements, +1 in case n is odd.
• Run a loop from x = 1 to n/2 (+1 in case n is odd).
• The idea is if we are picking x elements from part1, then we need to pick (n/2 (+1 in case n is odd) – x) elements from part2.
• We already have stored the generated subset and its sum for ni elements. Iterate on the sums generated using x elements in part1. For each sum S in P1[x], we need a sum closest to (∑arr)/2 – S in part2 using the remaining elements (n/2 (+1 in case n is odd) – x). This is where binary search can be leveraged to quickly find the closest sum in part2 for sums in part1. Once found the closest sum in Part2.
• The sum of subset1 is ∑ S1 = S + part2 index, where part2 index is the index returned by binary search.
• The sum of subset2 is ∑ S2 = TotalSum of the array – subset1 sum.
• If minimum difference abs( ∑ S1 – ∑ S2 ) is found. Store the corresponding generated subsets indices from part1 and part2
• Once subset1 is generated. Initialize a Boolean vector of size n and mark all the indices of subset1, also update the indices to their corresponding values in the subset1 vector.
• Iterate the Boolean vector after marking the subset1 indices and store the values corresponding to the non-marked indices in the Boolean vector.
• Print the minimum difference, subset1, and subset2.

Below is the implementation for the above approach:

## C++

 `#include ` `using` `namespace` `std;`   `struct` `Info {` `    ``int` `sum;` `    ``vector<``int``> indices;` `};`   `static` `bool` `cmp(Info& p1, Info& p2)` `{` `    ``return` `p1.sum < p2.sum;` `}`   `void` `generate(vector<``int``>& arr, ``int` `curr, ``int` `n, ``int` `sum,` `              ``vector >& store,` `              ``vector<``int``> build)` `{` `    ``if` `(curr == n) {` `        ``int` `sz = build.size();` `        ``store[sz].push_back({ sum, build });` `        ``return``;` `    ``}` `    ``build.push_back(curr);` `    ``generate(arr, curr + 1, n, sum + arr[curr], store,` `             ``build);` `    ``build.pop_back();` `    ``generate(arr, curr + 1, n, sum, store, build);` `}`   `int` `BINRY_SRCH(vector& arr, ``int` `target)` `{`   `    ``// Lower bound` `    ``int` `res = -1;` `    ``int` `low = 0;` `    ``int` `high = arr.size() - 1;` `    ``while` `(low <= high) {` `        ``int` `mid = (low + high) / 2;` `        ``if` `(arr[mid].sum >= target) {` `            ``res = mid;` `            ``high = mid - 1;` `        ``}` `        ``else` `{` `            ``low = mid + 1;` `        ``}` `    ``}` `    ``return` `res;` `}`   `vector > minDifference(vector<``int``>& arr, ``int` `n)` `{` `    ``int` `extra = (n % 2 != 0);`   `    ``vector > part1(n / 2 + 1 + extra);` `    ``vector > part2(n / 2 + 1);`   `    ``generate(arr, 0, n / 2 + extra, 0, part1, {});` `    ``generate(arr, n / 2 + extra, n, 0, part2, {});`   `    ``for` `(``auto``& vec : part2) {`   `        ``// Sorting part2 to prepare` `        ``// for binary search` `        ``sort(vec.begin(), vec.end(), cmp);` `    ``}`   `    ``vector > res(2);`   `    ``int` `diff = INT_MAX;` `    ``int` `TS = accumulate(arr.begin(), arr.end(), 0);`   `    ``// Making subset1` `    ``for` `(``int` `ele = 1; ele <= n / 2 + extra; ele++) {`   `        ``// Taking only ele` `        ``// elements from part1` `        ``vector P1 = part1[ele];`   `        ``// Taking rest of the elements` `        ``// for subset1 from part2` `        ``vector P2 = part2[n / 2 + extra - ele];`   `        ``// Iterating for each sum in P1` `        ``for` `(``auto` `x : P1) {`   `            ``// P1sum -> subset1 sum` `            ``// P2sum -> subset2 sum`   `            ``// For absolute minimisation,` `            ``// each subset should be having` `            ``// sum close to TS/2. If we` `            ``// take x sum from Part1, then` `            ``// remaining sum TS/2-x should` `            ``// be taken from part2. We` `            ``// want to get a sum closer to` `            ``// this target. For this, do` `            ``// binary search.` `            ``int` `index = BINRY_SRCH(P2, TS / 2 - x.sum);` `            ``if` `(index != -1) {` `                ``int` `subset1_Sum = x.sum + P2[index].sum;` `                ``int` `subset2_Sum = TS - subset1_Sum;`   `                ``if` `(``abs``(subset1_Sum - subset2_Sum) < diff) {` `                    ``diff = ``abs``(subset1_Sum - subset2_Sum);`   `                    ``// Storing the subset` `                    ``vector<``int``> subset1 = x.indices;` `                    ``for` `(``auto` `c : P2[index].indices) {` `                        ``subset1.push_back(c);` `                    ``}` `                    ``res = subset1;` `                ``}` `            ``}`   `            ``if` `(index > 0) {` `                ``index--;` `                ``int` `subset1_Sum = x.sum + P2[index].sum;` `                ``int` `subset2_Sum = TS - subset1_Sum;`   `                ``if` `(``abs``(subset1_Sum - subset2_Sum) < diff) {` `                    ``diff = ``abs``(subset1_Sum - subset2_Sum);`   `                    ``// Storing the subset` `                    ``vector<``int``> subset1 = x.indices;` `                    ``for` `(``auto` `c : P2[index].indices) {` `                        ``subset1.push_back(c);` `                    ``}` `                    ``res = subset1;` `                ``}` `            ``}` `        ``}` `    ``}`   `    ``// Find subset2 after ignoring elements` `    ``// of subset1 in arr`   `    ``vector<``bool``> vis(n, ``false``);`   `    ``for` `(``int` `i = 0; i < res.size(); i++) {` `        ``vis[res[i]] = ``true``;` `        ``res[i] = arr[res[i]];` `    ``}`   `    ``vector<``int``> subset2;` `    ``for` `(``int` `i = 0; i < n; i++) {` `        ``if` `(vis[i] == ``false``) {` `            ``subset2.push_back(arr[i]);` `        ``}` `    ``}` `    ``res = subset2;`   `    ``cout << ``"Min Difference "` `<< diff << endl;`   `    ``return` `res;` `}`   `void` `PRINT(vector >& subsets)` `{` `    ``cout << ``"Subset 1 : "``;` `    ``for` `(``auto` `x : subsets) {` `        ``cout << x << ``"  "``;` `    ``}` `    ``cout << endl` `         ``<< ``"Subset 2 : "``;` `    ``for` `(``auto` `x : subsets) {` `        ``cout << x << ``"  "``;` `    ``}` `}`   `// Drivers code` `int` `main()` `{` `    ``vector<``int``> arr;` `    ``vector > res;`   `    ``arr = {45, 34, 4, 12, 5, 2 };` `    ``res = minDifference(arr, arr.size());` `    ``PRINT(res);` `    ``return` `0;` `}`   `// Author:- RainX (Abhijit Roy, NIT AGARTALA)`

## Python3

 `def` `find_min_subset_sum_diff(arr):` `    ``total_sum ``=` `sum``(arr)` `    ``n ``=` `len``(arr)` `    ``dp ``=` `[[``False` `for` `_ ``in` `range``(total_sum``+``1``)] ``for` `_ ``in` `range``(n``+``1``)]`   `    ``for` `i ``in` `range``(n``+``1``):` `        ``dp[i][``0``] ``=` `True`   `    ``for` `i ``in` `range``(``1``, total_sum``+``1``):` `        ``dp[``0``][i] ``=` `False`   `    ``for` `i ``in` `range``(``1``, n``+``1``):` `        ``for` `j ``in` `range``(``1``, total_sum``+``1``):` `            ``dp[i][j] ``=` `dp[i``-``1``][j]` `            ``if` `arr[i``-``1``] <``=` `j:` `                ``dp[i][j] |``=` `dp[i``-``1``][j``-``arr[i``-``1``]]`   `    ``diff ``=` `float``(``'inf'``)` `    ``for` `j ``in` `range``(total_sum``/``/``2``, ``-``1``, ``-``1``):` `        ``if` `dp[n][j]:` `            ``diff ``=` `total_sum ``-` `(``2``*``j)` `            ``break`   `    ``subset1_sum ``=` `(total_sum ``+` `diff) ``/``/` `2` `    ``subset2_sum ``=` `total_sum ``-` `subset1_sum` `    ``subset1 ``=` `[]` `    ``subset2 ``=` `[]` `    ``i ``=` `n` `    ``j ``=` `subset1_sum` `    ``while` `j > ``0` `and` `i > ``0``:` `        ``if` `dp[i``-``1``][j] ``=``=` `False``:` `            ``subset1.append(arr[i``-``1``])` `            ``j ``-``=` `arr[i``-``1``]` `        ``else``:` `            ``subset2.append(arr[i``-``1``])` `        ``i ``-``=` `1`   `    ``print``(``"Min Difference:"``, diff)` `    ``print``(``"Subset 1 :"``, ``*``subset1)` `    ``print``(``"Subset 2 :"``, ``*``subset2)`   `arr ``=` `[``34``, ``45``, ``12``, ``4``, ``5``, ``2``]` `find_min_subset_sum_diff(arr)`

## Java

 `import` `java.util.Arrays;`   `public` `class` `Main {` `    ``public` `static` `void` `main(String[] args) {` `        ``int``[] arr = {``34``, ``45``, ``12``, ``4``, ``5``, ``2``};` `        ``findMinSubsetSumDiff(arr);` `    ``}`   `    ``public` `static` `void` `findMinSubsetSumDiff(``int``[] arr) {` `        ``int` `totalSum = ``0``;` `        ``for` `(``int` `i : arr) {` `            ``totalSum += i;` `        ``}`   `        ``int` `n = arr.length;` `        ``boolean``[][] dp = ``new` `boolean``[n + ``1``][totalSum + ``1``];`   `        ``for` `(``int` `i = ``0``; i <= n; i++) {` `            ``dp[i][``0``] = ``true``;` `        ``}`   `        ``for` `(``int` `i = ``1``; i <= totalSum; i++) {` `            ``dp[``0``][i] = ``false``;` `        ``}`   `        ``for` `(``int` `i = ``1``; i <= n; i++) {` `            ``for` `(``int` `j = ``1``; j <= totalSum; j++) {` `                ``dp[i][j] = dp[i - ``1``][j];` `                ``if` `(arr[i - ``1``] <= j) {` `                    ``dp[i][j] |= dp[i - ``1``][j - arr[i - ``1``]];` `                ``}` `            ``}` `        ``}`   `        ``int` `diff = Integer.MAX_VALUE;` `        ``for` `(``int` `j = totalSum / ``2``; j >= ``0``; j--) {` `            ``if` `(dp[n][j]) {` `                ``diff = totalSum - (``2` `* j);` `                ``break``;` `            ``}` `        ``}`   `        ``int` `subset1Sum = (totalSum + diff) / ``2``;` `        ``int` `subset2Sum = totalSum - subset1Sum;` `        ``int``[] subset1 = ``new` `int``[n];` `        ``int``[] subset2 = ``new` `int``[n];` `        ``int` `i_ = n;` `        ``int` `j_ = subset1Sum;` `        ``int` `index1 = ``0``, index2 = ``0``;` `        ``while` `(j_ > ``0` `&& i_ > ``0``) {` `            ``if` `(dp[i_ - ``1``][j_] == ``false``) {` `                ``subset1[index1] = arr[i_ - ``1``];` `                ``index1++;` `                ``j_ -= arr[i_ - ``1``];` `            ``} ``else` `{` `                ``subset2[index2] = arr[i_ - ``1``];` `                ``index2++;` `            ``}` `            ``i_--;` `        ``}`   `        ``System.out.println(``"Min Difference: "` `+ diff);` `        ``System.out.print(``"Subset 1: "``);` `        ``for` `(``int` `k = index1 - ``1``; k >= ``0``; k--) {` `            ``System.out.print(subset1[k] + ``" "``);` `        ``}` `        ``System.out.print(``"\nSubset 2: "``);` `        ``for` `(``int` `k = index2 - ``1``; k >= ``0``; k--) {` `            ``System.out.print(subset2[k] + ``" "``);` `        ``}` `    ``}` `}`

## C#

 `using` `System;`   `public` `class` `Program` `{` `    ``public` `static` `void` `Main()` `    ``{` `        ``int``[] arr = {34, 45, 12, 4, 5, 2};` `        ``FindMinSubsetSumDiff(arr);` `    ``}`   `    ``public` `static` `void` `FindMinSubsetSumDiff(``int``[] arr)` `    ``{` `        ``int` `totalSum = 0;` `        ``foreach` `(``int` `i ``in` `arr)` `        ``{` `            ``totalSum += i;` `        ``}`   `        ``int` `n = arr.Length;` `        ``bool``[,] dp = ``new` `bool``[n + 1, totalSum + 1];`   `        ``for` `(``int` `i = 0; i <= n; i++)` `        ``{` `            ``dp[i, 0] = ``true``;` `        ``}`   `        ``for` `(``int` `i = 1; i <= totalSum; i++)` `        ``{` `            ``dp[0, i] = ``false``;` `        ``}`   `        ``for` `(``int` `i = 1; i <= n; i++)` `        ``{` `            ``for` `(``int` `j = 1; j <= totalSum; j++)` `            ``{` `                ``dp[i, j] = dp[i - 1, j];` `                ``if` `(arr[i - 1] <= j)` `                ``{` `                    ``dp[i, j] |= dp[i - 1, j - arr[i - 1]];` `                ``}` `            ``}` `        ``}`   `        ``int` `diff = ``int``.MaxValue;` `        ``for` `(``int` `j = totalSum / 2; j >= 0; j--)` `        ``{` `            ``if` `(dp[n, j] == ``true``)` `            ``{` `                ``diff = totalSum - (2 * j);` `                ``break``;` `            ``}` `        ``}`   `        ``int` `subset1Sum = (totalSum + diff) / 2;` `        ``int` `subset2Sum = totalSum - subset1Sum;` `        ``int``[] subset1 = ``new` `int``[n];` `        ``int``[] subset2 = ``new` `int``[n];` `        ``int` `i_ = n;` `        ``int` `j_ = subset1Sum;` `        ``int` `index1 = 0, index2 = 0;` `        ``while` `(j_ > 0 && i_ > 0)` `        ``{` `            ``if` `(dp[i_ - 1, j_] == ``false``)` `            ``{` `                ``subset1[index1] = arr[i_ - 1];` `                ``index1++;` `                ``j_ -= arr[i_ - 1];` `            ``}` `            ``else` `            ``{` `                ``subset2[index2] = arr[i_ - 1];` `                ``index2++;` `            ``}` `            ``i_--;` `        ``}`   `        ``Console.WriteLine(``"Min Difference: "` `+ diff);` `        ``Console.Write(``"Subset 1: "``);` `        ``for` `(``int` `k = index1 - 1; k >= 0; k--)` `        ``{` `            ``Console.Write(subset1[k] + ``" "``);` `        ``}` `        ``Console.Write(``"\nSubset 2: "``);` `        ``for` `(``int` `k = index2 - 1; k >= 0; k--)` `        ``{` `            ``Console.Write(subset2[k] + ``" "``);` `        ``}` `    ``}` `}`

## Javascript

 `function` `findMinSubsetSumDiff(arr) {` `  ``let totalSum = arr.reduce((a, b) => a + b);` `  ``let n = arr.length;` `  ``let dp = Array.from(Array(n + 1), () => Array(totalSum + 1));`   `  ``for` `(let i = 0; i <= n; i++) {` `    ``dp[i] = ``true``;` `  ``}`   `  ``for` `(let i = 1; i <= totalSum; i++) {` `    ``dp[i] = ``false``;` `  ``}`   `  ``for` `(let i = 1; i <= n; i++) {` `    ``for` `(let j = 1; j <= totalSum; j++) {` `      ``dp[i][j] = dp[i - 1][j];` `      ``if` `(arr[i - 1] <= j) {` `        ``dp[i][j] |= dp[i - 1][j - arr[i - 1]];` `      ``}` `    ``}` `  ``}`   `  ``let diff = Number.MAX_SAFE_INTEGER;` `  ``for` `(let j = Math.floor(totalSum / 2); j >= 0; j--) {` `    ``if` `(dp[n][j] == ``true``) {` `      ``diff = totalSum - (2 * j);` `      ``break``;` `    ``}` `  ``}`   `  ``let subset1Sum = (totalSum + diff) / 2;` `  ``let subset2Sum = totalSum - subset1Sum;` `  ``let subset1 = [];` `  ``let subset2 = [];` `  ``let i_ = n;` `  ``let j_ = subset1Sum;` `  ``let index1 = 0,` `    ``index2 = 0;`   `  ``while` `(j_ > 0 && i_ > 0) {` `    ``if` `(dp[i_ - 1][j_] == ``false``) {` `      ``subset1[index1] = arr[i_ - 1];` `      ``index1++;` `      ``j_ -= arr[i_ - 1];` `    ``} ``else` `{` `      ``subset2[index2] = arr[i_ - 1];` `      ``index2++;` `    ``}` `    ``i_--;` `  ``}`   `  ``console.log(``"Min Difference: "` `+ diff);` `  ``console.log(``"Subset 1: "` `+ subset1.reverse().join(``" "``));` `  ``console.log(``"Subset 2: "` `+ subset2.reverse().join(``" "``));` `}`   `let arr = [34, 45, 12, 4, 5, 2];` `findMinSubsetSumDiff(arr);`

Output

```Min Difference 0
Subset 1 : 34  12  5
Subset 2 : 45  4  2  ```

Time Complexity: O( 2n/2  * log(2n/2) *  n/2 ),  O(2n/2) is for generating two subsets, O(log(2n/2)) for binary searching for each element of part1 in part2, hence the extra n/2 factor.
Auxiliary Space: O(2n/2), 2n/2 space is required for storing the half subset.