Given a set of integers, the task is to divide it into two sets S1 and S2 such that the absolute difference between their sums is minimum.
If there is a set S with n elements, then if we assume Subset1 has m elements, Subset2 must have n-m elements and the value of abs(sum(Subset1) – sum(Subset2)) should be minimum.
Example:
Input: arr[] = {1, 6, 11, 5}
Output: 1
Explanation:
Subset1 = {1, 5, 6}, sum of Subset1 = 12
Subset2 = {11}, sum of Subset2 = 11
This problem is mainly an extension to the Dynamic Programming| Set 18 (Partition Problem).
Recursive Solution:
The recursive approach is to generate all possible sums from all the values of the array and to check which solution is the most optimal one. To generate sums we either include the i’th item in set 1 or don’t include, i.e., include in set 2.
C++
#include <bits/stdc++.h>
using namespace std;
int findMinRec( int arr[], int i, int sumCalculated,
int sumTotal)
{
if (i == 0)
return abs ((sumTotal - sumCalculated)
- sumCalculated);
return min(
findMinRec(arr, i - 1, sumCalculated + arr[i - 1],
sumTotal),
findMinRec(arr, i - 1, sumCalculated, sumTotal));
}
int findMin( int arr[], int n)
{
int sumTotal = 0;
for ( int i = 0; i < n; i++)
sumTotal += arr[i];
return findMinRec(arr, n, 0, sumTotal);
}
int main()
{
int arr[] = { 3, 1, 4, 2, 2, 1 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << "The minimum difference between two sets is "
<< findMin(arr, n);
return 0;
}
|
Java
import java.util.*;
class GFG {
public static int findMinRec( int arr[], int i,
int sumCalculated,
int sumTotal)
{
if (i == 0 )
return Math.abs((sumTotal - sumCalculated)
- sumCalculated);
return Math.min(
findMinRec(arr, i - 1 ,
sumCalculated + arr[i - 1 ],
sumTotal),
findMinRec(arr, i - 1 , sumCalculated,
sumTotal));
}
public static int findMin( int arr[], int n)
{
int sumTotal = 0 ;
for ( int i = 0 ; i < n; i++)
sumTotal += arr[i];
return findMinRec(arr, n, 0 , sumTotal);
}
public static void main(String[] args)
{
int arr[] = { 3 , 1 , 4 , 2 , 2 , 1 };
int n = arr.length;
System.out.print( "The minimum difference"
+ " between two sets is "
+ findMin(arr, n));
}
}
|
Python3
def findMinRec(arr, i, sumCalculated,
sumTotal):
if (i = = 0 ):
return abs ((sumTotal - sumCalculated) -
sumCalculated)
return min (findMinRec(arr, i - 1 ,
sumCalculated + arr[i - 1 ],
sumTotal),
findMinRec(arr, i - 1 ,
sumCalculated, sumTotal))
def findMin(arr, n):
sumTotal = 0
for i in range (n):
sumTotal + = arr[i]
return findMinRec(arr, n,
0 , sumTotal)
if __name__ = = "__main__" :
arr = [ 3 , 1 , 4 , 2 , 2 , 1 ]
n = len (arr)
print ( "The minimum difference " +
"between two sets is " ,
findMin(arr, n))
|
C#
using System;
class GFG {
public static int findMinRec( int [] arr, int i,
int sumCalculated,
int sumTotal)
{
if (i == 0)
return Math.Abs((sumTotal - sumCalculated)
- sumCalculated);
return Math.Min(
findMinRec(arr, i - 1,
sumCalculated + arr[i - 1],
sumTotal),
findMinRec(arr, i - 1, sumCalculated,
sumTotal));
}
public static int findMin( int [] arr, int n)
{
int sumTotal = 0;
for ( int i = 0; i < n; i++)
sumTotal += arr[i];
return findMinRec(arr, n, 0, sumTotal);
}
public static void Main()
{
int [] arr = { 3, 1, 4, 2, 2, 1 };
int n = arr.Length;
Console.Write( "The minimum difference"
+ " between two sets is "
+ findMin(arr, n));
}
}
|
Javascript
<script>
function findMinRec(arr, i, sumCalculated, sumTotal)
{
if (i == 0)
return Math.abs((sumTotal-sumCalculated) -
sumCalculated);
return Math.min(findMinRec(arr, i - 1, sumCalculated
+ arr[i-1], sumTotal),
findMinRec(arr, i-1,
sumCalculated, sumTotal));
}
function findMin(arr, n)
{
let sumTotal = 0;
for (let i = 0; i < n; i++)
sumTotal += arr[i];
return findMinRec(arr, n, 0, sumTotal);
}
let arr=[3, 1, 4, 2, 2, 1];
let n = arr.length;
document.write( "The minimum difference" +
" between two sets is " +
findMin(arr, n));
</script>
|
Output
The minimum difference between two sets is 1
Time Complexity:
All the sums can be generated by either
(1) including that element in set 1.
(2) without including that element in set 1.
So possible combinations are :-
arr[0] (1 or 2) -> 2 values
arr[1] (1 or 2) -> 2 values
.
.
.
arr[n] (2 or 2) -> 2 values
So time complexity will be 2*2*..... *2 (For n times),
that is O(2^n).
Auxiliary Space: O(n), extra space for the recursive function call stack.
An approach using Memoization:
Simplify the process by considering the concepts of taking and not taking elements. There is no requirement to combine two arrays, as you can obtain the difference by subtracting one element from the total sum. The objective is to find the minimum difference.
C++
#include <iostream>
#include <vector>
using namespace std;
int f( int idx, int sum, int arr[], int n, int totalSum,
vector<vector< int > >& dp)
{
if (idx == n) {
return abs ((totalSum - sum) - sum);
}
if (dp[idx][sum] != -1) {
return dp[idx][sum];
}
int pick
= f(idx + 1, sum + arr[idx], arr, n, totalSum, dp);
int notPick = f(idx + 1, sum, arr, n, totalSum, dp);
return dp[idx][sum] = min(pick, notPick);
}
int findMin( int arr[], int n)
{
int totalSum = 0;
for ( int i = 0; i < n; i++) {
totalSum += arr[i];
}
vector<vector< int > > dp(n + 1,
vector< int >(totalSum + 1, -1));
return f(0, 0, arr, n, totalSum, dp);
}
int main()
{
int arr[] = { 3, 1, 4, 2, 2, 1 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << "The minimum difference between two sets is "
<< findMin(arr, n);
return 0;
}
|
Java
import java.util.Arrays;
class GFG {
public static int f( int idx, int sum, int [] arr, int n,
int totalSum, int [][] dp)
{
if (idx == n) {
return Math.abs((totalSum - sum) - sum);
}
if (dp[idx][sum] != - 1 ) {
return dp[idx][sum];
}
int pick = f(idx + 1 , sum + arr[idx], arr, n,
totalSum, dp);
int notPick = f(idx + 1 , sum, arr, n, totalSum, dp);
return dp[idx][sum] = Math.min(pick, notPick);
}
public static int findMin( int [] arr, int n)
{
int totalSum = 0 ;
for ( int i = 0 ; i < n; i++) {
totalSum += arr[i];
}
int [][] dp = new int [n + 1 ][totalSum + 1 ];
for ( int [] row : dp) {
Arrays.fill(row, - 1 );
}
return f( 0 , 0 , arr, n, totalSum, dp);
}
public static void main(String[] args)
{
int [] arr = { 3 , 1 , 4 , 2 , 2 , 1 };
int n = arr.length;
System.out.println(
"The minimum difference between two sets is "
+ findMin(arr, n));
}
}
|
Python
def findMin(arr, n):
totalSum = sum (arr)
dp = [[ - 1 for _ in range (totalSum + 1 )] for _ in range (n + 1 )]
def f(idx, sum , arr, n, totalSum, dp):
if idx = = n:
return abs ((totalSum - sum ) - sum )
if dp[idx][ sum ] ! = - 1 :
return dp[idx][ sum ]
pick = f(idx + 1 , sum + arr[idx], arr, n, totalSum, dp)
notPick = f(idx + 1 , sum , arr, n, totalSum, dp)
dp[idx][ sum ] = min (pick, notPick)
return dp[idx][ sum ]
return f( 0 , 0 , arr, n, totalSum, dp)
if __name__ = = "__main__" :
arr = [ 3 , 1 , 4 , 2 , 2 , 1 ]
n = len (arr)
print ( "The minimum difference between two sets is" , findMin(arr, n))
|
C#
using System;
class MinimumSubsetDifference {
static int FindMin( int [] arr, int n)
{
int totalSum = 0;
for ( int i = 0; i < n; i++) {
totalSum += arr[i];
}
int [][] dp = new int [n + 1][];
for ( int i = 0; i <= n; i++) {
dp[i] = new int [totalSum + 1];
for ( int j = 0; j <= totalSum; j++) {
dp[i][j] = -1;
}
}
return F(0, 0, arr, n, totalSum, dp);
}
static int F( int idx, int sum, int [] arr, int n,
int totalSum, int [][] dp)
{
if (idx == n) {
return Math.Abs((totalSum - sum) - sum);
}
if (dp[idx][sum] != -1) {
return dp[idx][sum];
}
int pick = F(idx + 1, sum + arr[idx], arr, n,
totalSum, dp);
int notPick = F(idx + 1, sum, arr, n, totalSum, dp);
return dp[idx][sum] = Math.Min(pick, notPick);
}
static void Main()
{
int [] arr = { 3, 1, 4, 2, 2, 1 };
int n = arr.Length;
Console.WriteLine(
"The minimum difference between two sets is "
+ FindMin(arr, n));
}
}
|
Javascript
function f(idx, sum, arr, n, totalSum, dp)
{
if (idx == n) {
return Math.abs((totalSum - sum) - sum);
}
if (dp[idx][sum] != -1) {
return dp[idx][sum];
}
let pick
= f(idx + 1, sum + arr[idx], arr, n, totalSum, dp);
let notPick = f(idx + 1, sum, arr, n, totalSum, dp);
return dp[idx][sum] = Math.min(pick, notPick);
}
function findMin(arr, n)
{
let totalSum = 0;
for (let i = 0; i < n; i++) {
totalSum += arr[i];
}
let dp = new Array(n+1);
for (let i=0; i<n+1; i++)
dp[i]= new Array(totalSum+1).fill(-1);
return f(0, 0, arr, n, totalSum, dp);
}
let arr = [ 3, 1, 4, 2, 2, 1 ];
let n = arr.length;
console.log( "The minimum difference between two sets is " , findMin(arr, n));
|
Output
The minimum difference between two sets is 1
Time Complexity: O(n*sum) where n is the number of elements and sum is the sum of all elements.
Auxiliary Space: O(n*sum)
An approach using dynamic Programming:
The problem can be solved using dynamic programming when the sum of the elements is not too big. We can create a 2D array dp[n+1][sum+1] where n is the number of elements in a given set and sum is the sum of all elements. We can construct the solution in a bottom-up manner.
The task is to divide the set into two parts.
We will consider the following factors for dividing it.
Let
dp[i][j] = {1 if some subset from 1st to i'th has a sum
equal to j
0 otherwise}
i ranges from {1..n}
j ranges from {0..(sum of all elements)}
So
dp[i][j] will be 1 if
1) The sum j is achieved including i'th item
2) The sum j is achieved excluding i'th item.
Let sum of all the elements be S.
To find Minimum sum difference, we have to find j such
that Min{sum - 2*j : dp[n][j] == 1 }
where j varies from 0 to sum/2
The idea is, sum of S1 is j and it should be closest
to sum/2, i.e., 2*j should be closest to sum (as this will ideally minimize sum-2*j.
Below is the implementation of the above code.
C++
#include <bits/stdc++.h>
using namespace std;
int findMin( int arr[], int n)
{
int sum = 0;
for ( int i = 0; i < n; i++)
sum += arr[i];
bool dp[n + 1][sum + 1];
for ( int i = 0; i <= n; i++)
dp[i][0] = true ;
for ( int i = 1; i <= sum; i++)
dp[0][i] = false ;
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j <= sum; 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_MAX;
for ( int j = sum / 2; j >= 0; j--) {
if (dp[n][j] == true ) {
diff = sum - 2 * j;
break ;
}
}
return diff;
}
int main()
{
int arr[] = { 3, 1, 4, 2, 2, 1 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << "The minimum difference between 2 sets is "
<< findMin(arr, n);
return 0;
}
|
Java
import java.io.*;
class GFG {
static int findMin( int arr[], int n)
{
int sum = 0 ;
for ( int i = 0 ; i < n; i++)
sum += arr[i];
boolean dp[][] = new boolean [n + 1 ][sum + 1 ];
for ( int i = 0 ; i <= n; i++)
dp[i][ 0 ] = true ;
for ( int i = 1 ; i <= sum; i++)
dp[ 0 ][i] = false ;
for ( int i = 1 ; i <= n; i++) {
for ( int j = 1 ; j <= sum; 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 = sum / 2 ; j >= 0 ; j--) {
if (dp[n][j] == true ) {
diff = sum - 2 * j;
break ;
}
}
return diff;
}
public static void main(String[] args)
{
int arr[] = { 3 , 1 , 4 , 2 , 2 , 1 };
int n = arr.length;
System.out.println(
"The minimum difference between 2 sets is "
+ findMin(arr, n));
}
}
|
Python3
import sys
def findMin(a, n):
su = 0
su = sum (a)
dp = [[ 0 for i in range (su + 1 )]
for j in range (n + 1 )]
for i in range (n + 1 ):
dp[i][ 0 ] = True
for j in range ( 1 , su + 1 ):
dp[ 0 ][j] = False
for i in range ( 1 , n + 1 ):
for j in range ( 1 , su + 1 ):
dp[i][j] = dp[i - 1 ][j]
if a[i - 1 ] < = j:
dp[i][j] | = dp[i - 1 ][j - a[i - 1 ]]
diff = sys.maxsize
for j in range (su / / 2 , - 1 , - 1 ):
if dp[n][j] = = True :
diff = su - ( 2 * j)
break
return diff
a = [ 3 , 1 , 4 , 2 , 2 , 1 ]
n = len (a)
print ( "The minimum difference between "
"2 sets is " , findMin(a, n))
|
C#
using System;
class GFG {
static int findMin( int [] arr, int n)
{
int sum = 0;
for ( int i = 0; i < n; i++)
sum += arr[i];
bool [, ] dp = new bool [n + 1, sum + 1];
for ( int i = 0; i <= n; i++)
dp[i, 0] = true ;
for ( int i = 1; i <= sum; i++)
dp[0, i] = false ;
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j <= sum; 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 = sum / 2; j >= 0; j--) {
if (dp[n, j] == true ) {
diff = sum - 2 * j;
break ;
}
}
return diff;
}
public static void Main(String[] args)
{
int [] arr = { 3, 1, 4, 2, 2, 1 };
int n = arr.Length;
Console.WriteLine( "The minimum difference "
+ "between 2 sets is "
+ findMin(arr, n));
}
}
|
Javascript
<script>
function findMin(arr, n)
{
let sum = 0;
for (let i = 0; i < n; i++)
sum += arr[i];
let dp = new Array(n + 1);
for (let i = 0; i <= n; i++) {
dp[i] = new Array(sum + 1);
for (let j = 0; j <= sum; j++) {
if (j == 0)
dp[i][j] = true ;
}
}
for (let i = 1; i <= sum; i++)
dp[0][i] = false ;
for (let i=1; i<=n; i++)
{
for (let j=1; j<=sum; 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_VALUE;
for (let j=Math.floor(sum/2); j>=0; j--)
{
if (dp[n][j] == true )
{
diff = sum-2*j;
break ;
}
}
return diff;
}
let arr = [ 3, 1, 4, 2, 2, 1 ];
let n = arr.length;
document.write( "The minimum difference between 2 sets is "
+ findMin(arr, n));
</script>
|
Output
The minimum difference between 2 sets is 1
Time Complexity = O(n*sum) where n is the number of elements and sum is the sum of all elements.
Auxiliary Space: O(n*sum)
An approach using dynamic Programming with less Space Complexity:
Instead of using 2D array we can solve this problem using 1D array dp[sum/2+1]. Lets say sum of elements of set 1 is x than sum of elements of set 2 will be sm-x (sm is sum of all elements of arr). So we have to minimize abs(sm-2*x). So for minimizing difference between two sets, we need to know a number that is just less than sum/2 (sum is sum of all elements in array) and can be generated by addition of elements from array.
C++
#include <iostream>
using namespace std;
int minDifference( int arr[], int n)
{
int sum = 0;
for ( int i = 0; i < n; i++)
sum += arr[i];
int y = sum / 2 + 1;
bool dp[y], dd[y];
for ( int i = 0; i < y; i++) {
dp[i] = dd[i] = false ;
}
dp[0] = true ;
for ( int i = 0; i < n; i++) {
for ( int j = 0; j + arr[i] < y; j++) {
if (dp[j])
dd[j + arr[i]] = true ;
}
for ( int j = 0; j < y; j++) {
if (dd[j])
dp[j] = true ;
dd[j] = false ;
}
}
for ( int i = y - 1; i >= 0; i--) {
if (dp[i])
return (sum - 2 * i);
}
}
int main()
{
int arr[] = { 1, 6, 11, 5 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << "The Minimum difference of 2 sets is "
<< minDifference(arr, n) << '\n' ;
return 0;
}
|
Java
import java.util.*;
class GFG {
static int minDifference( int arr[], int n)
{
int sum = 0 ;
for ( int i = 0 ; i < n; i++)
sum += arr[i];
int y = sum / 2 + 1 ;
boolean dp[] = new boolean [y], dd[]
= new boolean [y];
for ( int i = 0 ; i < y; i++) {
dp[i] = dd[i] = false ;
}
dp[ 0 ] = true ;
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j + arr[i] < y; j++) {
if (dp[j])
dd[j + arr[i]] = true ;
}
for ( int j = 0 ; j < y; j++) {
if (dd[j])
dp[j] = true ;
dd[j] = false ;
}
}
for ( int i = y - 1 ; i >= 0 ; i--) {
if (dp[i])
return (sum - 2 * i);
}
return 0 ;
}
public static void main(String[] args)
{
int arr[] = { 1 , 6 , 11 , 5 };
int n = arr.length;
System.out.print(
"The Minimum difference of 2 sets is "
+ minDifference(arr, n) + '\n' );
}
}
|
Python3
def minDifference(arr, n):
sum = 0
for i in range (n):
sum + = arr[i]
y = sum / / 2 + 1
dp = [ False for i in range (y)]
dd = [ False for i in range (y)]
dp[ 0 ] = True
for i in range (n):
for j in range (y):
if (j + arr[i] < y and dp[j]):
dd[j + arr[i]] = True
for j in range (y):
if (dd[j]):
dp[j] = True
dd[j] = False
for i in range (y - 1 , 0 , - 1 ):
if (dp[i]):
return ( sum - 2 * i)
return 0
if __name__ = = '__main__' :
arr = [ 1 , 6 , 11 , 5 ]
n = len (arr)
print ( "The Minimum difference of 2 sets is " , minDifference(arr, n))
|
C#
using System;
public class GFG {
static int minDifference( int [] arr, int n)
{
int sum = 0;
for ( int i = 0; i < n; i++)
sum += arr[i];
int y = sum / 2 + 1;
bool [] dp = new bool [y];
bool [] dd = new bool [y];
for ( int i = 0; i < y; i++) {
dp[i] = dd[i] = false ;
}
dp[0] = true ;
for ( int i = 0; i < n; i++) {
for ( int j = 0; j + arr[i] < y; j++) {
if (dp[j])
dd[j + arr[i]] = true ;
}
for ( int j = 0; j < y; j++) {
if (dd[j])
dp[j] = true ;
dd[j] = false ;
}
}
for ( int i = y - 1; i >= 0; i--) {
if (dp[i])
return (sum - 2 * i);
}
return 0;
}
public static void Main(String[] args)
{
int [] arr = { 1, 6, 11, 5 };
int n = arr.Length;
Console.Write( "The Minimum difference of 2 sets is "
+ minDifference(arr, n) + '\n' );
}
}
|
Javascript
<script>
function minDifference(arr , n) {
var sum = 0;
for ( var i = 0; i < n; i++)
sum += arr[i];
var y = parseInt(sum / 2) + 1;
var dp = Array(y).fill( false ), dd = Array(y).fill( false );
for ( var i = 0; i < y; i++) {
dp[i] = dd[i] = false ;
}
dp[0] = true ;
for ( var i = 0; i < n; i++)
{
for ( var j = 0; j + arr[i] < y; j++) {
if (dp[j])
dd[j + arr[i]] = true ;
}
for ( var j = 0; j < y; j++) {
if (dd[j])
dp[j] = true ;
dd[j] = false ;
}
}
for ( var i = y - 1; i >= 0; i--) {
if (dp[i])
return (sum - 2 * i);
}
return 0;
}
var arr = [ 1, 6, 11, 5 ];
var n = arr.length;
document.write( "The Minimum difference of 2 sets is " + minDifference(arr, n) + '\n' );
</script>
|
Output
The Minimum difference of 2 sets is 1
Time Complexity: O(n*sum)
Auxiliary Space: O(sum)
Note that the above solution is in Pseudo Polynomial Time (time complexity is dependent on the numeric value of input). Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
16 Oct, 2023
Like Article
Save Article