Question:
You are given an array/list ‘ARR’ of ‘N’ positive integers and an integer ‘K’. Your task is to check if there exists a subset in ‘ARR’ with a sum equal to ‘K’.
Note: Return true if there exists a subset with sum equal to ‘K’. Otherwise, return false.
For Example :
If ‘ARR’ is {1,2,3,4} and ‘K’ = 4, then there exists 2 subsets with sum = 4. These are {1,3} and {4}. Hence, return true.
Sample Input 1:
2
4 5
4 3 2 1
5 4
2 5 1 6 7
Sample Output 1:
true
false
Explanation For Sample Input 1:
In example 1, ‘ARR’ is {4,3,2,1} and ‘K’ = 5. There exist 2 subsets with sum = 5. These are {4,1} and {3,2}. Hence, return true.
In example 2, ‘ARR’ is {2,5,1,6,7} and ‘K’ = 4. There are no subsets with sum = 4. Hence, return false.
Solution:
Recursion and Memoized
TC: O(n * target)
SC: O(n * target) + O(n) ← [stack space]
public class Solution {
public static boolean subsetSumToK ( int n , int target , int arr []){
//2-D which will contain indexes from 0 to n-1 and target from 0 to target
int [][] dp = new int [n][target + 1 ];
for ( int [] row : dp){
Arrays. fill (row, - 1 );
}
return subsetSumUtil (arr, 0 , target, dp);
}
public static boolean subsetSumUtil ( int [] arr , int idx , int target , int [][] dp ){
if (target == 0 ){
return true ;
}
if (idx >= arr.length || target < 0 ){
return false ;
}
if (dp[idx][target] != - 1 ){
return dp[idx][target] == 1 ;
}
boolean noCall = subsetSumUtil (arr, idx + 1 , target, dp);
boolean yesCall = subsetSumUtil (arr, idx + 1 , target - arr[idx], dp);
dp[idx][target] = (noCall || yesCall) ? 1 : 0 ;
return noCall || yesCall;
}
}
Tabulation:
At (i, j) we define meaning as till ith array index can we achieve jth target ??
public static boolean subsetSumToK ( int n, int target, int arr[]){
//2-D which will contain indexes from 0 to n-1 and target from 0 to target
boolean [][] dp = new boolean [n + 1 ][target + 1 ];
//Base case
for ( int i = 0 ; i <= n; i ++ ){
dp[i][ 0 ] = true ;
}
for ( int i = 1 ; i <= n; i ++ ){
for ( int j = 1 ; j <= target; j ++ ){
//If we don't include the current element
dp[i][j] = dp[i - 1 ][j]; //Whatever the answer was till the last element
//if the current target is greater than current element then only we can subtract the target
//and check at the previous result of previous row if it was achieved or not.
if (j >= arr[i - 1 ]){
dp[i][j] = dp[i][j] || dp[i - 1 ][j - arr[i - 1 ]];
}
}
}
return dp[n][target];
}
Space Optimized:
public static boolean subsetSumToK ( int n, int target, int arr[]){
//2-D which will contain indexes from 0 to n-1 and target from 0 to target
boolean [] prev = new boolean [target + 1 ];
boolean [] curr = new boolean [target + 1 ];
//Base case
prev[ 0 ] = true ; //true for target zero
for ( int j = 1 ; j <= target; j ++ ){
prev[j] = false ;
}
curr[ 0 ] = true ; // A sum of 0 is always possible
for ( int j = 1 ; j <= target; j ++ ){
curr[j] = false ; //baaki toh assign false, because these will be filled in the below loop
}
for ( int i = 1 ; i <= n; i ++ ){
for ( int j = 1 ; j <= target; j ++ ){
//If we don't include the current element
curr[j] = prev[j]; //Whatever the answer was till the last element
//if the current target is greater than current element then only we can subtract the target
//and check at the previous result of previous row if it was achieved or not.
if (j >= arr[i - 1 ]){
curr[j] = curr[j] || prev[j - arr[i - 1 ]];
}
}
prev = curr. clone ();
}
return prev[target];
}