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