LC 416. Partition Equal Subset Sum

Sarthak Sehgal · March 23, 2020

Solution

Let’s say the sum of all elements in the array is totSum. The array can be partitioned into two equal halves only if totSum is even. Further, there should be a subset having sum = totSum/2. The first part, calculating totSum and imposing the even condition, is easy. How to check whether a subset having sum equal to totSum/2 exists? This can be solved using backtracking where we consider two cases: element i is in subset and element i is not in the subset and then recurse. This will take up lot of time though. Note that we essentially have to find a whether some elements from the input array make up the sum = totSum/2 - this problem is like the 0/1 knapsack problem which is classically solved using a 2D DP (it can also be solved using 1D DP but here I will only mention 2D DP solution). Define a 2D vector dp where dp[i][j] denotes whether sum=j can be formed using input[1..i]. Let’s take an example, let input = [1, 5, 11, 5]. Here, totSum = 22 so we have to find a subset having sum=11. Let us define out 2D array as below:

    0 1 2 3 4 5 6 7 8 9 10 11
    1 0 0 0 0 0 0 0 0 0 0  0 
1:  1 1 0 0 0 0 0 0 0 0 0  0 
5:  1 1 0 0 0 1 1 0 0 0 0  0 
11: 1 1 0 0 0 1 1 0 0 0 0  1 
5:  1 1 0 0 0 1 1 0 0 0 1  1 

Here the columns represent sum from 0 to 11 and the rows represent the input elements used. The first row indicates that no input element is used. dp[i][j] = 1 if the specific sum j can be gotten from the first i numbers. If we can pick such a series of numbers from 0-i whose sum is j, dp[i][j] is true (=1), otherwise it is false (=0).
Transition function: For each number, if we don’t pick it, dp[i][j] = dp[i-1][j], which means if the first i-1 elements has made it to j, dp[i][j] would also make it to j (we can just ignore nums[i-1]). If we pick nums[i-1], dp[i][j] = dp[i-1][j-nums[i-1]], which represents that j is composed of the current value nums[i] and the remaining composed of other previous numbers. Thus, the transition function is dp[i][j] = dp[i-1][j]   dp[i-1][j-nums[i-1]].
bool canPartition(vector<int>& nums) {
    int totSum=0;
    for (int i : nums)
        totSum+=i;
    
    if (totSum&1 || totSum<2)
        return false;
    
    int subsetSum = totSum/2;
    vector<vector<bool>> v(nums.size()+1, vector<bool>(subsetSum+1, false));
    
    for (int i=0; i<=nums.size(); i++)
        v[i][0] = true;
    for (int i=1; i<=nums.size(); i++) {
        for (int j=1; j<=subsetSum; j++) {
            v[i][j] = v[i-1][j];
            if (j-nums[i-1]>=0)
                v[i][j]=v[i][j]||v[i-1][j-nums[i-1]];
            if (j==subsetSum && v[i][j])
                return true;
        }
    }
    
    return false;
}

Time complexity: O(nm) where n is the size of nums and m is the total sum of the numbers Space complexity: O(nm)

Twitter, Facebook