01背包理论
二维:
dp[i][j]
知道dp二维数组中i和j的关系以及含义,i是当前要放的物品,j就是当前背包的容量
在二维数组中,各行的数据是隔离开来的,所以背包容量部分,从后往前和从前往后都是一样的
背包和物品的遍历可以互换
一维:
dp[j]
理解j的含义
容量为j的背包所能得到的最大价值为dp[j]
一维数组每次都是重复利用,而且是有更新的
背包容量部分的遍历只能从后往前遍历,不然会出现不符合01背包的物品只能用一次的规则
只能先遍历物品,在遍历背包
416. 分割等和子集
思路:看成价值和重量是相同的
用一维,dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i])
dp只能初始化为0
本题要求集合里能否出现总和为 sum / 2 的子集
如果最大价值是 sum / 2,说明正好被商品装满了
代码:
class Solution {
public boolean canPartition(int[] nums) {
//考的就是01背包问题
if(nums==null||nums.length==0){
return false;
}
int n=nums.length;
int sum=0;
for(int num:nums){
sum+=num;
}
if(sum%2!=0){//如果总和除以2的还有余数,就表明这个总和不能平方,故不符合题目条件
return false;
}
int target=sum/2;//由题目知道,要分为两个数组,使得两个数组的和相同,所以先用总和除以2
int[] dp=new int[target+1];//直接初始化为target个大小,最后因为平方的原因,所以当dp[target]==target时,就表明可以平方。
for(int i=0;i<n;i++){
for(int j=target;j>=nums[i];j--){//因为一维数组的原因,所以要倒序遍历背包容量,不然会出现同一个数重复利用的问题,可以自己画图画个数组出来看一下。
dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
if(dp[target]==target){
return true;
}
return false;
}
}