LeetCode416分割等和子集
416. 分割等和子集 - 力扣(LeetCode)
这道题属于01背包的变形,我们首先根据题意将其转换为01背包问题,01背包的意思是在容量为W的背包中每个物品只能选一次所能容纳的最大价值,这道题的意思是在容量为W的背包中能否选择一定物品使其恰好装满。
01背包的状态转移方程:$$dp[i] [j] = max(dp[i - 1] [j], dp[i - 1] [j - w[i]] + v[i]) $$ 根据01背包的状态转移方程我们可以得出这道题的状态转移方程。首先这道题问的是否能恰好装满,所以dp数组为bool类型,然后我们根据题目要求来确定状态,$$dp[i] [j] $$ 表示选取前i件物品能否是容量为j的背包恰好装满。根据01背包我们可以得出我们的状态转移方程。$$dp[i] [j] = dp[i - 1] [j] || dp[i - 1] [j - nums[i]] $$
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
int n = nums.size();
for (int i = 0; i < n; ++ i)
sum += nums[i];
if (sum & 1) return false;
sum /= 2;
vector<vector<bool>> dp(n + 1, vector<bool>(sum + 1, false));
//dp(i)(j)表示选取第i件物品,背包空间为j能否恰好为真
//dp(i)(j) = dp(i - 1)(j) || dp(i - 1)(j - nums[i])
dp[0][0] = true; //表示什么都不选,空间为0,一定为真
for (int i = 1; i <= n; ++ i) {
for (int j = 0; j <= sum; ++ j) {
dp[i][j] = dp[i - 1][j];
if (j >= nums[i - 1])
dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i - 1]];
}
}
return dp[n][sum];
}
};
我们可以利用滚动数组将其优化到一维的情况。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
int n = nums.size();
for (int i = 0; i < n; ++ i)
sum += nums[i];
if (sum & 1) return false;
sum /= 2;
vector<bool> dp(sum + 1, false);
dp[0] = true; //表示什么都不选,空间为0,一定为真
for (int i = 1; i <= n; ++ i) {
for (int j = sum; j >= nums[i - 1]; -- j) {
dp[j] = dp[j] || dp[j - nums[i - 1]];
}
}
return dp[sum];
}
};
浙公网安备 33010602011771号