题目链接:416. 分割等和子集
文章讲解:代码随想录 416. 分割等和子集讲解
视频讲解:动态规划之背包问题,这个包能装满吗?| LeetCode:416.分割等和子集
思路和解法
题目:
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
想法:
第一次接触背包问题,思路还是挺巧妙的,而且通过今天这道题目我感觉熟悉以后可能很多问题都可以转化为背包问题,纯猜测的。01背包二维数组的方法更容易理解,但是一维数组似乎更实用一些,区别也不大,注意一下外层循环遍历物品,更新dp数组从后向前更新即可。
class Solution {
public:
//核心思路:如果能凑出和为所有数字求和的一半,就说明可以分割成功
//凑的过程简化为01背包问题,每个数字只能选一次,每个数字就是物品价值,同时也是物品重量
//假设有一个背包容量为sum/2,就看数字能不能刚好填满背包
//其实直接想似乎不需要价值,但因为背包问题有价值,那就不妨假设数字同时也是物品价值
bool canPartition(vector<int>& nums) {
//数组长度<=200 数字<=100,求和就小于等于20000,一半就小于等于10000
// 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;
vector<int> dp(target + 1, 0);
//一维数组 背包问题 外层循环遍历物品 一维数组要从后往前遍历 防止一个物品多次加入
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]);
}
}
if (dp[target] == target) return true;
return false;
}
};