01背包,完全背包和多重背包都是从01背包进化而来。所以01背包才是关键。
很明显:概念需要记下来,显然的区别是物品的个数不同。
01背包:n种物品,每种物品只有一个;
完全背包:n种物品,每种物品有无限个;
多重背包:n种物品,每种物品的个数各不相同。
动规五部曲:
dp[i][j]:[0, i] 的物品任取放入容量为j的背包(所能得到的最大价值);
LeetCode:
1.思路
求和,取模判断偶数,剪枝;
将数组作为物品,将target作为背包,判断是否存在物品之和为target的情况存在。每个物品只能用一次,因此背包采用倒序的方式。
2.代码实现
class Solution {
public boolean canPartition(int[] nums) {
// 求和,判偶数,剪枝
int target = 0;
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
if (sum % 2 != 0) {
return false;
}
target = sum / 2;
// 初始化dp[]数值
int[] dp = new int[target + 1]; // 动态规划数组,dp[i]表示是否可以组成和为i的子集
for (int i = 0; i < nums.length; i++) {
for (int j = target; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]); // 更新dp[j]的值,表示是否可以组成和为j的子集
}
if (dp[target] == target) { // 如果dp[target]等于目标和,则表示可以分割成两个相等的子集
return true;
}
}
return dp[target] == target; // 返回dp[target]是否等于目标和
}
}
3.复杂度分析
时间复杂度:O(n^2).
空间复杂度:O(n).