###### tags: `Leetcode` `medium` `dynamic programming` `python` `c++` `Top 100 Liked Questions`
# 416. Partition Equal Subset Sum
## [題目連結:] https://leetcode.com/problems/partition-equal-subset-sum/
## 題目:
Given a **non-empty** array nums containing **only positive integers**, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
**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.
```
## 解題想法:
* 此題為判斷數組是否能拆成兩部分使得兩部分和相等
* 使用dp:
* 定義**dp[i][j]**: **從nums[0]~nums[i]中,取隨意個數,能否構成j**
* dp[i][j]= **dp[ i-1 ][j]** or **dp[ i-1 ][ j-nums[i] ]**
* 對於遍歷到nums[i]時候:
* case dp[i-1][j]: **先前nums[0]~nums[i-1]之數字總和可構成j**
* 則不用取nums[i],依然可以總和為j
* case dp[i-1][j-nums[i]]: **先前nums[0]~nums[i-1]之數字總和可構成 j-nums[i]**
* 則表示取了nums[i]後,可以構成總和j
* 流程:
* **Step1**: 初始判斷
* 若數組長度不足2 or 總和為奇數,則為False
* **Step2**: 初始dp
* **dp[i][0]=True**: 構成0只要不取任何數即可
* **dp[0][nums[0]]=True**: 構成nums[0],只要取nums[0]即可
* **Step3**: 填入dp
## Python:
``` python=
class Solution(object):
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
'''
dp[i][j]: 從nums[0]~nums[i]中 取隨意個數 能否構成j
dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i]]
遍歷到i位置時:
case dp[i-1][j]: 前面i-1之數字總和可構成j: 則不用取nums[i],依然可以總和為j
case dp[i-1][j-nums[i]] 前面i-1之數字總和可構成 j-nums[i]: 則表示取了nums[i]後,可以構成總和j
初始:
dp[i][0]:True 構成0只要不取任何數即可
dp[0][nums[0]]: True 構成nums[0]只要取nums[0]即可
'''
if len(nums)<2:
return False
total=sum(nums)
if total%2!=0: #若一半為奇數 也不用搞了
return False
target=total//2
#不能用target+1,因為有可能某個nums[i]大於target以上
dp= [[False]*(total+1) for _ in range(len(nums))]
#初始:
dp[0][nums[0]]=True
for i in range(len(nums)):
dp[i][0]=True
#填dp
for i in range(1,len(nums)):
for j in range(1,target+1):
if j-nums[i]>=0:
dp[i][j]=dp[i-1][j]|dp[i-1][j-nums[i]]
else:
dp[i][j]=dp[i-1][j]
return dp[-1][target]
nums = [1,5,11,5]
result=Solution()
ans=result.canPartition(nums)
print(ans)
```
## C++:
* vector總和使用 **accumulate**(first_index, last_index, initial value of sum);
``` cpp=
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n=nums.size();
if (n<2)
return false;
int sum=accumulate(nums.begin(), nums.end(), 0);
int target=sum/2;
if (sum%2 != 0)
return false;
//init dp
vector<vector<bool> > dp(n, vector<bool>(sum+1,false));
dp[0][nums[0]]=true;
for (int i=0; i<n; i++) dp[i][0]=true;
//dp
for (int i=1; i<n; i++){
for (int j=1; j<target+1; j++){
if (j-nums[i]>=0)
dp[i][j]= dp[i-1][j] || dp[i-1][j-nums[i]];
else
dp[i][j]=dp[i-1][j];
}
}
return dp.back()[target];
}
};
```