「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
416. 分割等和子集
题目描述
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入: nums = [1,5,11,5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入: nums = [1,2,3,5]
输出: false
解释: 数组不能分割成两个元素和相等的子集。
解析
/**
* @brief 01背包问题
* 动态规划:
* 1、确定dp数组以及下标的含义
* 01背包中,dp[i]表示:容量为j的背包,可以装下物品的总价值最大为 dp[i]
* 本题中:dp[i]表示:背包总容量为 i , 最大可以凑成i的子集总和为 dp[i]
* 2、确定递推公式
* 01背包中:dp[j] = max(dp[j],dp[j-weight[i]]+value[i]);
* 本题中:dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);
* 相当于背包里放入数值,物品 i 的重量为nums[i] , 价值也是 nums[i]
* 3、数组初始化
* 全部初始化为0
* 题述中,每个元素值不超100,数组元素个数不超200,总和则不超 20000
* 所以背包最大只需要其中一半,所以元素大小为10001即可
* vector<int> dp(10001,1);
* 4、确定遍历顺序
* 使用一维数组dp时。物品遍历的for循环放在外层,遍历背包的for循环放在内层,
* 且内层的for循环倒序
*
*/
代码
class Solution
{
public:
bool canPartition(vector<int> &nums)
{
// 进行排序
sort(nums.begin(), nums.end());
int sum = 0;
// 背包最大值为10001
vector<int> dp(10001, 0);
for (int i = 0; i < nums.size(); i++)
{
sum += nums[i];
}
// 如果总和为奇数,则不能等分
if (sum % 2 == 1)
{
return false;
}
// 等分后的背包重量
int target = sum / 2;
//01 背包
// 先进行物品遍历
for (int i = 0; i < nums.size(); i++)
{
// 再遍历背包
for (int j = target; j >= nums[i]; j--)
{
// 背包容量为j时,最大的价值
// 物品的重量为 nums[i],价值也为 nums[i]
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
if (dp[target] == target)
{
return true;
}
return false;
}
};