1049. 最后一块石头的重量 II
其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小
这样就化解成01背包问题了。
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for(int stone : stones){
sum += stone;
}
int target = sum / 2;
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 Math.abs(dp[target] - (sum - dp[target]));
}
}
494. 目标和
转化为01背包问题
问题转化为,装满容量为x的背包,有几种方法
这次和之前遇到的背包问题不一样了,之前都是求容量为j的背包,最多能装多少。
1.确定dp数组的含义
dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
2.递推关系
只要搞到nums[i],凑成dp[j]就有dp[j - nums[i]] 种方法
dp[j] += dp[j - nums[i]]
3. dp数组如何初始化
从递推公式可以看出,在初始化的时候dp[0] 一定要初始化为1,因为dp[0]是在公式中一切递推结果的起源
4. 确定遍历顺序
nums放在外循环,target在内循环,且内循环倒序
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int num : nums){
sum += num;
}
if((sum + target) % 2 != 0){
return 0;
}
if (target < 0 && sum < -target) return 0;
int goal = (sum + target) / 2;
if(goal < 0){
goal = -goal;
}
int[] dp = new int[goal + 1];
dp[0] = 1;
for(int i = 0; i < nums.length; i++){
for(int j = goal; j >= nums[i]; j--){
dp[j] += dp[j - nums[i]];
}
}
return dp[goal];
}
}
474. 一和零
但本题其实是01背包问题!
只不过这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品。
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
for(String str : strs){
int oneNum = 0;
int zeroNum = 0;
char[] chars = str.toCharArray();
for(char c : chars){
if(c == '0'){
zeroNum++;
}
if(c == '1'){
oneNum++;
}
}
for(int i = m; i >= zeroNum; i--){
for(int j = n; j >= oneNum; j--){
dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
return dp[m][n];
}
}