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 <= 200
1 <= nums[i] <= 100
Code
Top Down with memoization
Time Complexity: , Space Complexity:
注意 memo
的 size 為 。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if(sum & 1) return false;
int target = sum / 2;
int n = nums.size();
vector<vector<int>> memo(n, vector<int>(target + 1, -1));
return subsetSum(nums, memo, 0, target);
}
bool subsetSum(vector<int>& nums, vector<vector<int>>& memo, int idx, int sum) {
if(sum == 0) return true;
if(idx >= nums.size() || sum < 0) return false;
if(memo[idx][sum] != -1) return memo[idx][sum];
return memo[idx][sum] = (subsetSum(nums, memo, idx + 1, sum - nums[idx]) || subsetSum(nums, memo, idx + 1, sum));
}
};
DP
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if(sum % 2 != 0)
return false;
int target = sum / 2, n = nums.size();
/*
dp[i][j]: can use nums[0:i] to add up to j
so dp[i][0] = true because we can always use
0 to add up to 0.
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
dp[i - 1][j]: do not use nums[i - 1], use only nums[0: i - 2] to adds up to j;
dp[i - 1][j - nums[i - 1]]: use nums[i - 1], and use nums[0: i - 2] to adds up to j - nums[i - 1];
*/
vector<vector<bool>> dp(n + 1, vector<bool>(target + 1, false));
// base case
for(int i = 0; i < n + 1; i++)
dp[i][0] = true;
for(int i = 1; i < n + 1; i++) {
for(int j = 1; j < target + 1; j++) {
dp[i][j] = dp[i][j] || dp[i - 1][j];
if(j >= nums[i - 1])
dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i - 1]];
}
}
return dp[n][target];
}
};
DP-Optimized
Denote as target
, and as nums.size()
.
Time Complexity: , Space Complexity:
原本的遞迴關係式為:DP[i][j] = DP[i-1][j - nums[i - 1]] || DP[i-1][j]
等於說在 2D DP Table 當中,每一個格子都只和上一列左前方和正前方的格子有關係,又因為和左前方的格子有關係,因此要從最右邊開始填起(for(int j = target; j >= 1; j--)
)。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if(sum % 2 != 0) return false;
int target = sum / 2;
int n = nums.size();
int DP[target + 1];
memset(DP, 0, sizeof(DP));
DP[0] = 1;
for(int i = 1; i < n + 1; i++) {
for(int j = target; j >= 1; j--) {
if(j >= nums[i - 1]) {
if(DP[j - nums[i - 1]] == 1)
DP[j] = 1;
}
if(DP[j] == 1) DP[j] = 1;
}
}
return DP[target];
}
};