01背包问题 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
- 确定dp数组以及下标的含义:背包问题有一种写法, 是使用二维数组,即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
- 递推公式:考虑放入物品和不放物品两种情况。
416. 分割等和子集
这题要找是否能把子集分割成俩个相等的集合,所以把集合里的数求和sum以后除以2,能除开的话就算是可以分割成两个相同元素和子集了。
- 确定dp数组以及下标的含义:把这个问题当成01背包问题去思考,dp[i]表示当前第i个物品能装进背包的值,如果背包容量为target, dp[target]就是装满背包之后的重量。当dp[target]==target成立时,说明可以分割出一个等和子集。
- 确定递推公式:01背包的公式是dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);本题相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
- dp初始化:dp[0]=0
- 确定遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历
class Solution {
public boolean canPartition(int[] nums) {
int n = nums.length;
if(nums == null || n == 0) return false;
int sum = 0;
for(int i : nums){
sum += i;
}
int target = sum / 2;
if(sum % 2 != 0){
return false;
}
int[] dp = new int[target + 1];
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 dp[target] == target;
}
}