Given an array arr[] of size N and a given difference diff, the task is to count the number of partitions that we can perform such that the difference between the sum of the two subsets is equal to the given difference.
Note: A partition in the array means dividing an array into two parts say S1 and S2 such that the union of S1 and S2 is equal to the original array and each element is present in only of the subsets.
Examples:
Input: N = 4, arr[] = [5, 2, 6, 4], diff = 3
Output: 1
Explanation: We can only have a single partition which is shown below:
{5, 2} and {6, 4} such that S1 = 7 and S2 = 10 and thus the difference is 3Input: N = 5, arr[] = [1, 2, 3, 1, 2], diff = 1
Output: 5
Explanation: We can have five partitions which is shown below
{1, 3, 1} and {2, 2} – S1 = 5, S2 = 4
{1, 2, 2} and {1, 3} – S1 = 5, S2 = 4
{3, 2} and {1, 1, 2} – S1 = 5, S2 = 4
{1, 2, 2} and {1, 3} – S1 = 5, S2 = 4
{3, 2} and {1, 1, 2} – S1 = 5, S2 = 4
- Suppose the array is partiotioned in two subsets with sum S1 and S2, so we know that,
- S1 + S2 is the total sum array nums
- S1 – S2 is the given diff
- Subtracting the two equations we would get,
- sum – diff = (S1 + S2) – (S1 – S2) = 2*S2 . So, S2 = ( sum – diff ) / 2
- From this we get the idea that an element X can be partiotioned in only one way when the difference between the two partitions is given.
- Therefore, in this case of array the total number of possible ways depends on the number of possible ways to create a subset having sum S2.
So we can use the concept of recursion to generate all possible subsets with sum S2. For each element there are two choices: either be a part of the subset S2 or not.
In the above idea, there are conditions visible that must be satisfied for the subset to exist:
- The difference between array sum and diff must be a positive number and
- This value must be an even number (As this is the same as 2*S2).
Time Complexity: O(2N)
Auxiliary Space: O(N)
Efficient Approach: The idea is similar as the naive one. But here we will use the idea of dynamic programming to optimize the time complexity.
Upon close observation, it can be seen that any state can be uniquely defined unsing two parameters, one parameter represents the index, and the other one represents the sum (S2) of the subset formed using elements from the starting till that index.
So, we can count the number of ways to form the subset from each state and can reuse them to avoid repeated calculations.
Follow the steps mentioned below to implement the approach:
- Calculate the sum of the array.
- Create a 2 dimensional array dp[][] with dimension (N * array sum) to store the calculated value of each state.
-
Traverse the array using recursion and generate two calls.
- If the value for the state is already calculated, reuse the value.
-
Otherwise there are two cases:
- If adding the current element will not make the currentSum more than S2, then generate two calls, one with the current element added to the currentSum and the other without adding it.
- If adding the current element increases currentSum above S2, then we only generate one call without adding the current element.
- If the currentSum is equal to S2 then we return 1.
- Return the final value received in this way as the answer.
Below is the implementation of the above approach.
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std;
int dp[1001][10000];
// Function to implement dynamic programming concept // to count the total number of possible ways int countSubsets(vector< int >& v, int i, int S2,
int currentSum)
{ if (currentSum == S2) {
return 1;
}
if (i >= v.size()) {
return 0;
}
if (dp[i][currentSum] != -1) {
return dp[i][currentSum];
}
if (currentSum + v[i] > S2) {
return dp[i][currentSum]
= countSubsets(v, i + 1, S2, currentSum);
}
else {
return dp[i][currentSum]
= countSubsets(v, i + 1, S2,
currentSum + v[i])
+ countSubsets(v, i + 1, S2, currentSum);
}
} int countSub(vector< int >& vp, int N, int diff)
{ int sum = 0; // Calculating total sum
for ( auto & value : vp)
sum += value;
// edge cases
if (sum - diff < 0 || (sum - diff) % 2 == 1) {
return 0;
}
// let the two subsets be having sum s1, s2
// s1-s2 = D, where D is the difference
// s1+s2 = Sum, where Sum is total Sum
// s2 = (Sum-diff)/2
return countSubsets(vp, 0, (sum - diff) / 2, 0);
} // Driver code int main()
{ int N = 5;
vector< int > arr = { 1, 2, 3, 1, 2 };
int diff = 1;
memset (dp, -1, sizeof (dp));
// Function call
cout << countSub(arr, N, diff) << endl;
return 0;
} |
// Java program for above approach import java.util.*;
import java.util.Arrays;
class GFG
{ static int dp[][] = new int [ 1001 ][ 10000 ];
// Function to implement dynamic programming concept // to count the total number of possible ways static int countSubsets( int [] v, int i, int S2,
int currentSum)
{ if (currentSum == S2) {
return 1 ;
}
if (i >= v.length) {
return 0 ;
}
if (dp[i][currentSum] != - 1 ) {
return dp[i][currentSum];
}
if (currentSum + v[i] > S2) {
return dp[i][currentSum]
= countSubsets(v, i + 1 , S2, currentSum);
}
else {
return dp[i][currentSum]
= countSubsets(v, i + 1 , S2,
currentSum + v[i])
+ countSubsets(v, i + 1 , S2, currentSum);
}
} static int countSub( int [] vp, int N, int diff)
{ int sum = 0 ; // Calculating total sum
for ( int value : vp)
sum += value;
// edge cases
if (sum - diff < 0 || (sum - diff) % 2 == 1 ) {
return 0 ;
}
// let the two subsets be having sum s1, s2
// s1-s2 = D, where D is the difference
// s1+s2 = Sum, where Sum is total Sum
// s2 = (Sum-diff)/2
return countSubsets(vp, 0 , (sum - diff) / 2 , 0 );
} // Driver code public static void main(String[] args)
{ int N = 5 ;
int [] arr = { 1 , 2 , 3 , 1 , 2 };
int diff = 1 ;
for ( int i = 0 ; i < 1001 ; i++)
{
for ( int j = 0 ; j < 10000 ; j++)
{
dp[i][j] = - 1 ;
}
}
// Function call
System.out.print(countSub(arr, N, diff));
} } |
# python3 code to implement the approach dp = [[ - 1 for _ in range ( 10000 )] for _ in range ( 1001 )]
# Function to implement dynamic programming concept # to count the total number of possible ways def countSubsets(v, i, S2, currentSum):
global dp
if (currentSum = = S2):
return 1
if (i > = len (v)):
return 0
if (dp[i][currentSum] ! = - 1 ):
return dp[i][currentSum]
if (currentSum + v[i] > S2):
dp[i][currentSum] = countSubsets(v, i + 1 , S2, currentSum)
return dp[i][currentSum]
else :
dp[i][currentSum] = countSubsets(
v, i + 1 , S2, currentSum + v[i]) + countSubsets(v, i + 1 , S2, currentSum)
return dp[i][currentSum]
def countSub(vp, N, diff):
sum = 0 # Calculating total sum
for value in vp:
sum + = value
# edge cases
if ( sum - diff < 0 or ( sum - diff) % 2 = = 1 ):
return 0
# let the two subsets be having sum s1, s2
# s1-s2 = D, where D is the difference
# s1+s2 = Sum, where Sum is total Sum
# s2 = (Sum-diff)/2
return countSubsets(vp, 0 , ( sum - diff) / / 2 , 0 )
# Driver code if __name__ = = "__main__" :
N = 5
arr = [ 1 , 2 , 3 , 1 , 2 ]
diff = 1
# Function call
print (countSub(arr, N, diff))
# This code is contributed by rakeshsahni
|
// C# code to implement the approach using System;
class GFG {
static int [,] dp = new int [1001, 10000];
// Function to implement dynamic programming concept // to count the total number of possible ways static int countSubsets( int [] v, int i, int S2,
int currentSum)
{ if (currentSum == S2) {
return 1;
}
if (i >= v.Length) {
return 0;
}
if (dp[i, currentSum] != -1) {
return dp[i, currentSum];
}
if (currentSum + v[i] > S2) {
return dp[i, currentSum]
= countSubsets(v, i + 1, S2, currentSum);
}
else {
return dp[i, currentSum]
= countSubsets(v, i + 1, S2,
currentSum + v[i])
+ countSubsets(v, i + 1, S2, currentSum);
}
} static int countSub( int [] vp, int N, int diff)
{ int sum = 0; // Calculating total sum
foreach ( int value in vp)
sum += value;
// edge cases
if (sum - diff < 0 || (sum - diff) % 2 == 1) {
return 0;
}
// let the two subsets be having sum s1, s2
// s1-s2 = D, where D is the difference
// s1+s2 = Sum, where Sum is total Sum
// s2 = (Sum-diff)/2
return countSubsets(vp, 0, (sum - diff) / 2, 0);
} // Driver Code public static void Main()
{ int N = 5;
int [] arr = { 1, 2, 3, 1, 2 };
int diff = 1;
for ( int i = 0; i <1001; i++)
{
for ( int j = 0; j <10000; j++)
{
dp[i, j] = -1;
}
}
// Function call
Console.WriteLine(countSub(arr, N, diff));
} } // This code is contributed by code_hunt. |
<script> // JavaScript program for the above approach
var dp = new Array(10000);
// Loop to create 2D array using 1D array for ( var i = 0; i < dp.length; i++) {
dp[i] = new Array(1001);
} // Function to implement dynamic programming concept // to count the total number of possible ways function countSubsets(v, i, S2, currentSum)
{ if (currentSum == S2) {
return 1;
}
if (i >= v.length) {
return 0;
}
if (dp[i][currentSum] != -1) {
return dp[i][currentSum];
}
if (currentSum + v[i] > S2) {
return dp[i][currentSum]
= countSubsets(v, i + 1, S2, currentSum);
}
else {
return dp[i][currentSum]
= countSubsets(v, i + 1, S2,
currentSum + v[i])
+ countSubsets(v, i + 1, S2, currentSum);
}
} function countSub(vp, N, diff)
{ let sum = 0; // Calculating total sum
for (let value in vp)
sum += vp[value];
// edge cases
if (sum - diff < 0 || (sum - diff) % 2 == 1) {
return 0;
}
// let the two subsets be having sum s1, s2
// s1-s2 = D, where D is the difference
// s1+s2 = Sum, where Sum is total Sum
// s2 = (Sum-diff)/2
return countSubsets(vp, 0, Math.floor((sum - diff) / 2), 0);
} // Driver Code
let N = 5;
let arr = [ 1, 2, 3, 1, 2 ];
let diff = 1;
for ( i = 0; i <1001; i++)
{
for (let j = 0; j <10000; j++)
{
dp[i][j] = -1;
}
}
// Function call
document.write(countSub(arr, N, diff));
// This code is contributed by sanjoy_62. </script>
|
5
Time Complexity: O(N*(sum of the subset))
Auxiliary Space: O(N * array sum)
Another Approach:
- Start by including the necessary header files and defining the standard namespace.
- Define the function countSub that takes a vector of integers v, an integer n (denoting the size of the vector), and an integer diff as input parameters.
- Calculate the sum of all elements in the vector v using a for loop and store it in the variable sum.
- If the value of diff is greater than sum, then return 0 as it is impossible to form a subset with the required difference.
- If the sum of diff and sum is an odd number, then return 0 as it is not possible to divide the sum into two subsets with equal sums.
- Calculate the sum of the required subset (which will have a sum of (diff+sum)/2) and store it in the variable s2.
- Create a 2D array dp of size (n+1) x (s2+1) and initialize the first row with 1’s and the first column with 0’s.
- Use a nested for loop to fill the dp array using the dynamic programming approach. For each element dp[i][j], if v[i-1] (the value of the i-th element in the vector v) is greater than j, then copy the value of dp[i-1][j] to dp[i][j], else calculate the value of dp[i][j] as dp[i-1][j] + dp[i-1][j-v[i-1]].
- Return the value of dp[n][s2], which will be the number of possible subsets with the required difference.
- In the main function, define two test cases with their respective inputs and print the output of the countSub function for each test case.
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std;
int countSub(vector< int >& v, int n, int diff)
{ int sum = 0;
for ( int i = 0; i < n; i++)
sum += v[i];
if (diff > sum)
return 0;
if ((diff + sum) % 2 != 0)
return 0;
int s2 = (diff + sum) / 2;
int dp[n + 1][s2 + 1];
for ( int i = 0; i <= n; i++)
dp[i][0] = 1;
for ( int j = 1; j <= s2; j++)
dp[0][j] = 0;
for ( int i = 1; i <= n; i++) {
for ( int j = 0; j <= s2; j++) {
if (v[i - 1] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = dp[i - 1][j]
+ dp[i - 1][j - v[i - 1]];
}
}
return dp[n][s2];
} // Driver code int main()
{ int n, diff;
vector< int > v;
n = 5, diff = 1;
v = { 1, 2, 3, 1, 2 };
cout << countSub(v, n, diff) << endl;
return 0;
} |
// Java Implementation import java.util.*;
class Main {
public static int countSub(ArrayList<Integer> v, int n, int diff) {
int sum = 0 ;
for ( int i = 0 ; i < n; i++)
sum += v.get(i);
if (diff > sum)
return 0 ;
if ((diff + sum) % 2 != 0 )
return 0 ;
int s2 = (diff + sum) / 2 ;
int [][] dp = new int [n + 1 ][s2 + 1 ];
for ( int i = 0 ; i <= n; i++)
dp[i][ 0 ] = 1 ;
for ( int j = 1 ; j <= s2; j++)
dp[ 0 ][j] = 0 ;
for ( int i = 1 ; i <= n; i++) {
for ( int j = 0 ; j <= s2; j++) {
if (v.get(i - 1 ) > j)
dp[i][j] = dp[i - 1 ][j];
else
dp[i][j] = dp[i - 1 ][j] + dp[i - 1 ][j - v.get(i - 1 )];
}
}
return dp[n][s2];
}
public static void main(String[] args) {
int n, diff;
ArrayList<Integer> v = new ArrayList<>();
n = 5 ;
diff = 1 ;
v.add( 1 );
v.add( 2 );
v.add( 3 );
v.add( 1 );
v.add( 2 );
System.out.println(countSub(v, n, diff));
}
} // This code is contributed by Tapesh(tapeshdua420) |
# Python code to implement the approach def countSub(v, n, diff):
sum = 0
for i in range (n):
sum + = v[i]
if diff > sum :
return 0
if (diff + sum ) % 2 ! = 0 :
return 0
s2 = (diff + sum ) / / 2
dp = [[ 0 ] * (s2 + 1 ) for _ in range (n + 1 )]
for i in range (n + 1 ):
dp[i][ 0 ] = 1
for j in range ( 1 , s2 + 1 ):
dp[ 0 ][j] = 0
for i in range ( 1 , n + 1 ):
for j in range (s2 + 1 ):
if v[i - 1 ] > j:
dp[i][j] = dp[i - 1 ][j]
else :
dp[i][j] = dp[i - 1 ][j] + dp[i - 1 ][j - v[i - 1 ]]
return dp[n][s2]
# Driver Code n = 5
diff = 1
v = [ 1 , 2 , 3 , 1 , 2 ]
print (countSub(v, n, diff))
# This code is contributed by Tapesh(tapeshdua420) |
using System;
class Geek
{ static int CountSub( int [] v, int n, int diff)
{
int sum = 0;
for ( int i = 0; i < n; i++)
sum += v[i];
if (diff > sum)
return 0;
if ((diff + sum) % 2 != 0)
return 0;
int s2 = (diff + sum) / 2;
int [,] dp = new int [n + 1, s2 + 1];
for ( int i = 0; i <= n; i++)
dp[i, 0] = 1;
for ( int j = 1; j <= s2; j++)
dp[0, j] = 0;
for ( int i = 1; i <= n; i++)
{
for ( int j = 0; j <= s2; j++)
{
if (v[i - 1] > j)
dp[i, j] = dp[i - 1, j];
else
dp[i, j] = dp[i - 1, j] + dp[i - 1, j - v[i - 1]];
}
}
return dp[n, s2];
}
// Driver code
static void Main()
{
int n, diff;
int [] v;
n = 5;
diff = 1;
v = new int [] { 1, 2, 3, 1, 2 };
Console.WriteLine(CountSub(v, n, diff));
}
} |
// function to count total number of possible ways const countSub = (v, n, diff) => { let sum = 0;
// initial sum
for (let i = 0; i < n; i++)
sum += v[i];
// Base cases
if (diff > sum)
return 0;
if ((diff + sum) % 2 !== 0)
return 0;
let s2 = (diff + sum) / 2;
// array to store computations of subproblem
let dp = new Array(n + 1);
// Making dp 2d array
for (let i = 0; i <= n; i++)
dp[i] = new Array(s2 + 1);
// initalizing first row with 1
for (let i = 0; i <= n; i++)
dp[i][0] = 1;
// initalizing first column with 0
for (let j = 1; j <= s2; j++)
dp[0][j] = 0;
// filling dp array
for (let i = 1; i <= n; i++) {
for (let j = 0; j <= s2; j++) {
if (v[i - 1] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - v[i - 1]];
}
}
// Returning number of possible subsets with the required difference
return dp[n][s2];
} // Driver code let n, diff; let v; n = 5, diff = 1; v = [1, 2, 3, 1, 2]; console.log(countSub(v, n, diff)); |
5
Time Complexity: O(N * S), where N is the number of elements in the input vector and S is the sum of all the elements in the vector.
Auxiliary Space: O(N * S), as we are using a 2D array of size (N+1) x (S+1) to store the intermediate results of the dynamic programming approach.
Efficient approach : Space optimization
In previous approach the current value dp[i][j] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a single 1D array to store the computations.
Implementation:
// C++ code for above approach #include <bits/stdc++.h> using namespace std;
// Function to implement dynamic programming concept // to count the total number of possible ways int countSub(vector< int >& v, int n, int diff)
{ int sum = 0;
// initialize sum
for ( int i = 0; i < n; i++)
sum += v[i];
if (diff > sum)
return 0;
if ((diff + sum) % 2 != 0)
return 0;
int s2 = (diff + sum) / 2;
// create Dp to store the computations of subproblems
int dp[s2 + 1];
// initialize Dp with 0
for ( int i = 0; i <= s2; i++)
dp[i] = 0;
// Base case
dp[0] = 1;
// iterating over Dp to get the current
// value from previous computations
for ( int i = 0; i < n; i++) {
for ( int j = s2; j >= v[i]; j--) {
dp[j] += dp[j - v[i]];
}
}
// return answer
return dp[s2];
} // Driver code int main()
{ int n, diff;
vector< int > v;
n = 5, diff = 1;
v = { 1, 2, 3, 1, 2 };
// functions call
cout << countSub(v, n, diff) << endl;
return 0;
} |
import java.util.Arrays;
public class SubarraySumDifference {
// Function to implement dynamic programming concept
// to count the total number of possible ways
static int countSub( int [] v, int n, int diff) {
int sum = 0 ;
// initialize sum
for ( int i = 0 ; i < n; i++)
sum += v[i];
if (diff > sum)
return 0 ;
if ((diff + sum) % 2 != 0 )
return 0 ;
int s2 = (diff + sum) / 2 ;
// create dp to store the computations of subproblems
int [] dp = new int [s2 + 1 ];
// initialize dp with 0
Arrays.fill(dp, 0 );
// Base case
dp[ 0 ] = 1 ;
// iterating over dp to get the current
// value from previous computations
for ( int i = 0 ; i < n; i++) {
for ( int j = s2; j >= v[i]; j--) {
dp[j] += dp[j - v[i]];
}
}
// return answer
return dp[s2];
}
// Driver code
public static void main(String[] args) {
int n = 5 , diff = 1 ;
int [] v = { 1 , 2 , 3 , 1 , 2 };
// function call
System.out.println(countSub(v, n, diff));
}
} |
# Python Code Addition def countSub(v, n, diff):
sum = 0
# initialize sum
for i in range (n):
sum + = v[i]
if diff > sum :
return 0
if (diff + sum ) % 2 ! = 0 :
return 0
s2 = (diff + sum ) / / 2
# create Dp to store the computations of subproblems
dp = [ 0 ] * (s2 + 1 )
# Base case
dp[ 0 ] = 1
# iterating over Dp to get the current
# value from previous computations
for i in range (n):
for j in range (s2, v[i] - 1 , - 1 ):
dp[j] + = dp[j - v[i]]
# return answer
return dp[s2]
# Driver code n = 5
diff = 1
v = [ 1 , 2 , 3 , 1 , 2 ];
print (countSub(v, n, diff))
# This code is contributed by Tapesh(tapeshdua420) |
using System;
class Program {
// Function to implement dynamic programming concept
// to count the total number of possible ways
static int CountSub( int [] v, int n, int diff)
{
int sum = 0;
// Initialize sum
for ( int i = 0; i < n; i++)
sum += v[i];
if (diff > sum)
return 0;
if ((diff + sum) % 2 != 0)
return 0;
int s2 = (diff + sum) / 2;
// Create DP to store the computations of
// subproblems
int [] dp = new int [s2 + 1];
// Initialize DP with 0
for ( int i = 0; i <= s2; i++)
dp[i] = 0;
// Base case
dp[0] = 1;
// Iterating over DP to get the current
// value from previous computations
for ( int i = 0; i < n; i++) {
for ( int j = s2; j >= v[i]; j--) {
dp[j] += dp[j - v[i]];
}
}
// Return answer
return dp[s2];
}
// Driver code
static void Main()
{
int n, diff;
int [] v;
n = 5;
diff = 1;
v = new int [] { 1, 2, 3, 1, 2 };
// Function call
Console.WriteLine(CountSub(v, n, diff));
// Keep the console window open in debug mode.
Console.WriteLine( "Press any key to exit." );
Console.ReadKey();
}
} |
function countSub(v, n, diff) {
let sum = 0;
// Initialize sum
for (let i = 0; i < n; i++) {
sum += v[i];
}
if (diff > sum) {
return 0;
}
if ((diff + sum) % 2 !== 0) {
return 0;
}
let s2 = (diff + sum) / 2;
// Create dp to store the computations of subproblems
let dp = new Array(s2 + 1).fill(0);
// Base case
dp[0] = 1;
// Iterate over dp to get the current
// value from previous computations
for (let i = 0; i < n; i++) {
for (let j = s2; j >= v[i]; j--) {
dp[j] += dp[j - v[i]];
}
}
// Return answer
return dp[s2];
} // Driver code let n = 5; let diff = 1; let v = [1, 2, 3, 1, 2]; // Function call console.log(countSub(v, n, diff)); |
5
Time Complexity: O(N * S)
Auxiliary Space: O(S)