Problem Statement

Partition Equal Subset Sum - LeetCode Subset Sum Problem : Find if there is a subset in array whose sum equals target

Pattern: Pattern DP Subset Sum


Approach 1

Brute Force

public boolean canPartition (int[] nums){
	return f(nums, nums.length-1, 0, 0);
}
boolean f(int[] nums, int n, int sum1, int sum2) {
	if(n < 0) return sum1==sum2;		
	return f(nums, n-1, sum1+nums[n], sum2)
		|| f(nums, n-1, sum1, sum2+nums[n]);
}

TC : SC :

Memoised

int[][] cache;
public boolean canPartition (int[] nums){
	cache = new int[nums.length][20000+1];
	for(int[] row : cache) Arrays.fill(row, -1);
	return f(nums, nums.length-1, 0, 0);
}
 
boolean f(int[] nums, int n, int sum1, int sum2) {
	if(n < 0) return sum1==sum2;
	if(cache[n][sum1] != -1){ return cache[n][sum1] == 1;}
	
	boolean found = f(nums, n-1, sum1+nums[n], sum2)
				 || f(nums, n-1, sum1, sum2+nums[n]);
	cache[n][sum1] = found ? 1 : 0;
	return found;
}

TC : n*sum

Approach 2

Optimised Brute Force

public boolean canPartition(int[] nums) {  
   int sum = 0;  
   for (int num : nums) sum += num;  
   if(sum%2 != 0) return false;  
   return f(nums, nums.length - 1, sum/2);  
}  
  
boolean f(int[] nums, int n, int target) {  
   if (n < 0) return target == 0;  
   if(target == 0) return true;  
   if(nums[n] <= target) 
	   return f(nums, n - 1, target-nums[n]) || f(nums, n - 1, target);
   return f(nums, n - 1, target);
}
  • 2 partitions can be equal only if the sum is even
  • so simply track if a single sum/2 can be reached, by any subset in the array

Optimised Memoised

Boolean[][] cache;
 
public boolean canPartition(int[] nums) {
	int sum = 0;
	for (int num : nums) sum += num;
 
	if(sum%2 != 0) return false;
	cache = new Boolean[nums.length][sum/2+1];
 
	return f(nums, nums.length - 1, sum/2);
}
 
boolean f(int[] nums, int n, int target) {
	if (n < 0) return target == 0;
	if(target == 0) return true;
 
	if(cache[n][target] != null) return cache[n][target];
 
	if(nums[n] <= target) 
		cache[n][target] = f(nums, n - 1, target-nums[n]) || f(nums, n - 1, target);
	else 
		cache[n][target] = f(nums, n - 1, target);
	
	return cache[n][target];
}

TC : n*sum/2

Iterative

public boolean canPartition(int[] nums) {
	int k = 0, n = nums.length;
	for (int num : nums) k += num;
	if (k % 2 != 0) return false;
	k/=2;
 
	// init dp
	boolean dp[][] = new boolean[n + 1][k + 1];
	for (int j=0, i = 1; i < n+1; i++) dp[i][j] = true;
	// for (int j=1, i = 0; j < k+1; j++) dp[i][j] = false; // redundant
 
	for (int i = 1; i < n+1; i++)
		for (int j = 1; j < k + 1; j++)
			if(nums[i-1] <= j)
				dp[i][j] = dp[i-1][j-nums[i-1]] || dp[i-1][j];
			else dp[i][j] = dp[i-1][j];
	return dp[n][k];
}

TC :

Notes

if(nums[i-1] <= j)
	dp[i][j] = dp[i-1][j-nums[i-1]] || dp[i-1][j]; // 👈 what does this mean
else dp[i][j] = dp[i-1][j];
dp[ith item][sum equalling j] is true if either of the following is true	
- dp[i-1th item][sum = j  value of the ith item] is true
- dp[i-1th item][sum = j] is true