Problem Description
Given an integer array nums, return true if you can partition the array into two subsets such that the sum of the elements in both subsets is equal or false otherwise.
Example 1:
Input: nums = [1,5,11,5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: nums = [1,2,3,5] Output: false Explanation: The array cannot be partitioned into equal sum subsets.
Constraints:
1 <= nums.length <= 2001 <= nums[i] <= 100
Difficulty: Medium
Tags: array, dynamic programming
Rating: 97.98%
Solution
Here’s my Python solution to this problem:
#Problem 416: Partition Equal Subset Sum
class Solution:
def canPartition(self, nums: List[int]) -> bool:
n = len(nums)
s = sum(nums)
if s % 2 != 0: return False
t = s // 2
dp = [False] * (t+1)
dp[0] = True
for n in nums:
# We iterate from t to n-1 because we don't want to consider the same element twice
for j in range(t, n-1, -1):
# If we can make the sum j-n, we can make the sum j
dp[j] = dp[j] or dp[j-n]
return dp[t]
Key Insights
- If the total sum is odd, it’s impossible to split into equal halves
- We only need to find one subset that sums to half the total - the other subset will automatically have the same sum
- This is a variation of the 0/1 knapsack problem using dynamic programming
Solution Walkthrough
Let’s solve this step by step using the example: nums = [1, 5, 11, 5]
Step 1: Initial Checks
s = sum(nums) # s = 22
if s % 2 != 0: return False
t = s // 2 # t = 11 (our target sum)
Step 2: DP Array Setup
- We create a boolean array
dpof sizet + 1 dp[i]represents whether we can make sumiusing some elements from the array- Initially, only
dp[0] = True(we can always make sum 0 by selecting no elements)
Initial dp: [T, F, F, F, F, F, F, F, F, F, F, F]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11]
Step 3: Building the DP Array
For each number in our input array, we update the dp array:
- First number (1):
dp: [T, T, F, F, F, F, F, F, F, F, F, F]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11]
- Second number (5):
dp: [T, T, F, F, F, T, T, F, F, F, F, F]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11]
- Third number (11):
dp: [T, T, F, F, F, T, T, F, F, F, F, T]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11]
- Fourth number (5):
dp: [T, T, F, F, F, T, T, F, F, F, T, T]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11]
Key Line Explanation
dp[j] = dp[j] or dp[j-n]
This line means:
- We can make sum
jif either:- We could already make sum
jbefore (dp[j]) - We could make sum
j-nand add the current numbern
- We could already make sum
Why Iterate Backwards?
for j in range(t, n-1, -1)
We iterate backwards because:
- We want to use each number only once
- If we went forward, we might use the same number multiple times
- By going backwards, we ensure we only use new information from the previous iteration
Example Partitions
For our example [1, 5, 11, 5]:
- Target sum = 11
- One valid partition is:
- Subset 1: [1, 5, 5] = 11
- Subset 2: [11] = 11
Space and Time Complexity
- Time Complexity: = =
- Space Complexity: = =