分割等和子集
本文参考代码随想录
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100
思路
可以转换成01背包问题:
有一个 只能装重量为 sum / 2 的背包,商品为数字,这些数字能不能把 这个背包装满。一个数字只有一个维度,即 重量等于价值。
- 确定dp数组以及下标的含义
容量(所能装的重量)为j的背包,所背的物品价值最大可以为dp[j]。 - 确定递推公式
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); - dp数组如何初始化
首先dp[0]一定是0。本题题目中 只包含正整数的非空数组,所以非0下标的元素初始化为0就可以了。总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了 - 确定遍历顺序
如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历
class Solution {
public:bool canPartition(vector<int>& nums) {vector<int> dp(10001, 0);int sum = 0;for(int i = 0; i < nums.size(); i++){sum += nums[i];}if(sum % 2 == 1) return false;int target = sum / 2;for(int i = 0; i < nums.size(); i++){for(int j = target; j >= nums[i]; j--){dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);}}return dp[target] == target;}
};