1049. 最后一块石头的重量 II
思路:
见代码
代码:
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for(int num : stones){
sum += num;
}
//相当于把石头分成两拨,找总重量一半为背包容量的最大石头装载重量
int target = sum >> 1;
int[] dp = new int[target + 1];
for(int i = 0 ; i < stones.length; i++){
for(int j = target; j >= stones[i]; j--){
//每一块石头放或者不放
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - 2 * dp[target];
}
}
需要注意的点:
1、最后返回的结果
2、每一次放的时候是从前面容量小的背包推过来的,不需要担心容量超了。
494. 目标和
思路:
组合问题,不需要考虑顺序,递推时累加上一个状态(不加当前遍历的元素)的值
代码:
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int num : nums){
sum += num;
}
//target过于小,nums数组全都是负号也不满足时
if(target < 0 && sum < -target) return 0;
//举个例子,如果bagsize向下取整就会无解
if((target + sum) % 2 != 0) return 0;
//推导得出
//L-R=T;L+R=S联立,找出前面是正(负)号的背包容量
int bagsize = (target + sum)/2;
//dp[i]含义:和为i的组合数
int[] dp = new int[bagsize + 1];
//初始化为1时累加才会有结果
dp[0] = 1;
for(int i = 0; i < nums.length; i++){
for(int j = bagsize; j >= nums[i]; j--){
//和为j数字组合数是通过j-正在遍历的数字累加得来的
dp[j] += dp[j - nums[i]];
}
}
return dp[bagsize];
}
}
需要注意的点:
474.一和零
思路:
实质上还是0-1背包问题,多了一个背包维度。
代码:
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
//dp数组含义:含有m个0,n个1最大子集长度
int[][] dp = new int[m + 1][n + 1];
int onesize;
int zerosize;
//遍历物品
for(int k = 0; k < strs.length; k++){
onesize = 0;
zerosize = 0;
for(char ch : strs[k].toCharArray()){
if(ch == '0'){
zerosize++;
}else{
onesize++;
}
}
//遍历背包
for(int i = m; i >= zerosize; i--){
for(int j = n; j >= onesize; j--){
dp[i][j] = Math.max(dp[i][j],dp[i - zerosize][j - onesize] + 1);
}
}
}
return dp[m][n];
}
}