Solution: Partition Equal Subset Sum
Let's solve the Partition Equal Subset Sum problem using the Dynamic Programming pattern.
Statement
Given a non-empty array of positive integers, determine if the array can be divided into two subsets so that the sum of both subsets is equal.
Constraints:
-
nums.length
-
nums[i]
Solution
So far, you’ve probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which one to follow based on considerations such as time complexity and any implementation constraints.
Naive approach
We can solve this problem with the following two steps:
- First, we calculate the sum of the array. If the sum of the array is odd, there can’t be two subsets with an equal sum, so we return FALSE.
- If the sum is even, we calculate and find a subset of the array with a sum equal to .
The naive approach is to solve the second step using recursion. In this approach, we calculate the result repeatedly every time. For example, consider an array, [1, 6, 20, 7, 8]
, which can be partitioned into [1, 20]
and [6, 7, 8]
with the sum 21
. While computing the sum, we encounter 21
twice: once in the first subset (6 + 7 = 13, 13 + 8 = 21
) and once in the second subset (1 + 20 = 21
). However, since we’re not storing these sums, it is computed twice.
The time complexity of this approach is . In the worst case, for each element in an array, this solution tests two possibilities, i.e., whether to include or exclude it. We can avoid the repeated work done in the naive approach by storing the result calculated at each step. We store all the values in a lookup table.
Optimized approach using dynamic programming
We use the bottom-up approach of dynamic programming, also known as the tabulation technique. In this approach, the smallest problem is solved, the result is saved, and larger subproblems are computed based on the evaluated results. The problem is divided into subproblems, which are dependent on each other. We start by initializing a lookup table and setting up the values of the base cases. For every subsequent, larger subproblem, we fetch the results of the required preceding smaller subproblems and use them to get the solution to the current subproblem.
Here is how we implement this algorithm:
-
First, we calculate the sum of the array,
nums
. If the sum of the array is odd, there can’t be two subsets with an equal sum, so we return FALSE. -
Create a lookup table,
dp
, of size , where is the sum, and is the size of the array. Thedp[0][0]
represents that the sum is , and none of the elements is included in the sum. Therefore, rows and columns are needed. Initialize all cells ofdp
with FALSE. -
Since each element in the array is a positive number, therefore the sum of elements can’t be . Hence, each element of the first row in
dp
is set to TRUE to represent the solution of the smallest sub-problem. -
The FALSE in the first column except location indicates that an empty array has no subset whose sum is greater than .
-
Fill the table in a bottom-up approach where
[i][j]
represents the current row and column entry.-
If the
j
element of the array is greater thani
, it will make the sum greater thani
, which means we cannot include this element in our subset. Therefore, we copy the previous column’s value, which isdp[i][j-1]
, intodp[i][j]
. -
If the
j
element of the array is less than or equal toi
, we have two choices: either include it in our subset or exclude it. Here, we want to find out if it is possible to form a subset with a sum ofi
using the firstj
elements of the array.-
In the first choice, we need to find a subset that adds up to
i - nums[j-1]
using the firstj-1
elements of thenums
array. That means we are looking at the value ofdp[i - nums[j - 1]][j - 1]
. -
In the second choice, we exclude the
j
element from our subset and find a subset that adds up toi
using the firstj-1
elements of the nums array. This means we are looking at the value ofdp[i][j - 1]
. -
Finally, we set
dp[i][j]
to the logical OR of these two choices:dp[i][j] = dp[i - nums[j - 1]][j - 1] OR dp[i][j - 1]
.
-
-
-
Return the value present at the last row and last column of the
dp
, which denotes whether the array can be partitioned or not.- If we get TRUE, then the array can be partitioned.
- If we get FALSE, then the array can not be partitioned.
Here’s the demonstration of the steps above:
Level up your interview prep. Join Educative to access 80+ hands-on prep courses.