原题
Given a non-empty array 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.
Note:
- Each of the array element will not exceed 100.
- The array size will not exceed 200.
Example 1:
Input: [1, 5, 11, 5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: [1, 2, 3, 5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.
Reference Answer
思路分析
一个背包的题目,背包容量为数组中元素和的一半+1,这样只要看是否有元素可以正好填满背包即可.但是每个元素只能用一次,所以在尝试放一个元素的时候还要避免他对尝试放其他位置时对自己的影响.所以在尝试放一个元素到背包的时候需要从容量最大的位置开始,如果(当前位置-当前元素大小)位置可以通过放置之前的元素达到,则当前位置也可以通过放置当前元素正好达到这个位置.状态转移方程为:dp[i] = dp[i] || dp[i - nums[k]]
。
这道题用C++更容易实现和理解,用python怎么写怎么难受。
Code
class Solution:
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
# nums.sort()
if len(nums) == 1 or not nums:
return False
sum_count = sum(nums)
if sum_count % 2 != 0:
return False
target = sum_count // 2
dp = [False] * (target +1)
dp[0] = True
for count in nums:
for index in range(target, 0, -1):
if count > index:
break
dp[index] = dp[index] or dp[index - count]
return dp[target]
C++ version
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sums = accumulate(nums.begin(), nums.end(), 0);
if (sums & 1) return false;
int target = sums / 2;
vector<bool> dp(target+1, false);
dp[0] = true;
for(int i=0; i < nums.size(); i++){
for(int index = target; index >= nums[i]; index--){
dp[index] = dp[index] || dp[index - nums[i]];
}
}
return dp[target];
}
};
Note
accumulate(nums.begin(), nums.end(), 0)
是一种C++的求和手段,用于可迭代对象的求和,一共三个参数,第一个就是可迭代对象的开始位置,第二个为求和结束位置,第三个参数为初试加和项,这里设置为0,表示只求出nums和即可。- 这种题可联系背包问题进行求解。
参考文献
[1] https://blog.csdn.net/qq508618087/article/details/52774116