目录
1049. 最后一块石头的重量 II
本题就和 昨天的 416. 分割等和子集 很像了,可以尝试先自己思考做一做。
视频讲解:动态规划之背包问题,这个背包最多能装多少?LeetCode:1049.最后一块石头的重量II_哔哩哔哩_bilibili
题解思路:
本题简化模型仍然是01背包问题,但是不看卡哥视频说明,还真抽象不了01背包问题,因为本题的实质就是数字的碰撞游戏,而且还是任意两个数的碰撞,如果相同,则碰撞为0,如果不等,则碰撞后两数相减。因此了解后就会发现和分割等和子集问题非常相似,分割等和子集判断是否能把最大容量给装满,不同的是本题要把给定的数组元素装在背包容量大小为总数和一半的情况下,能装多少是多少,不一定要装满,那么就将总和分成两堆石头的重量,一堆是背包容量为总和一半值大小的背包装的重量dp[stones.length][target],另一堆就是剩余的重量sum - dp[stones.length][target],将这两堆相减就是石头碰撞后剩余总量的石头大小,但是解题过程中要注意以下两点:
1、石头的总重量如果为偶数,以[1,1,4]和[1,2,3]为例,总重量为6,因此背包的最大容量为3,但是背包容量所能装下的最大重量不一定为3,前者的最大重量是2,而后者最大重量是3,因为背包的容量还要取决于每块石头的重量,所有不能全盘否定总重量为偶数的时候,其最后一块石头的重量就是0;
2、要想计算碰撞后剩下的最小可能重量,其实可以简化成尽可能分成两堆问题,比如[3,3,3,4,5]分成9,9两堆,那么最后剩余的石头重量就是0;比如[3,3,3,4,6]分成9,8两堆,那么最后剩余的石头重量就是1
3、默认初始化dp[0][j] = 0:背包容量为j时,取第0块石头的时候背包重量的最大值;dp[i][0] = 0:背包容量为0时,取第i块石头的时候背包容量的最大值
class Solution {
public int lastStoneWeightII(int[] stones) {
//动规第一步:确定dp[i][j]数组的含义:在背包容量为j时,取第i块石头后此时背包重量的最大值
int sum = 0;
for(int i = 0 ; i < stones.length; i++){
sum += stones[i];
}
// if(sum % 2 == 0) return 0; //石头的总重量如果为偶数,以[1,1,4]和[1,2,3]为例,总重量为6,因此背包的最大容量为3,但是背包容量所能装下的最大重量不一定为3,前者的最大重量是2,而后者最大重量是3,因为背包的容量还要取决于每块石头的重量,所有不能全盘否定总重量为偶数的时候,其最后一块石头的重量就是0
int target = sum/2; //要想计算碰撞后剩下的最小可能重量,其实可以简化成尽可能分成两堆问题,比如[3,3,3,4,5]分成9,9两堆,那么最后剩余的石头重量就是0;比如[3,3,3,4,6]分成9,8两堆,那么最后剩余的石头重量就是1
int[][] dp = new int[stones.length + 1][target + 1]; //默认初始化dp[0][j] = 0:背包容量为j时,取第0块石头的时候背包重量的最大值;dp[i][0] = 0:背包容量为0时,取第i块石头的时候背包容量的最大值
for(int i = 1; i < dp.length; i++){
for(int j = 1; j < dp[0].length; j++){
if(j < stones[i-1]){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - stones[i-1]] + stones[i-1]);
}
}
}
int maxValue = dp[stones.length][target];//背包容量为总重量一半值的大小后,取到最后一块石头,此时背包的最大重量
return sum - maxValue - maxValue; //将石头分成两堆的重量:一堆石头的总重量为sum - dp[stones.length][target],另一堆尽可能装成总重量一半的重量为dp[stones.length][target]
}
}
494. 目标和(一刷卡住了)
大家重点理解 递推公式:dp[j] += dp[j - nums[i]],这个公式后面的提问 我们还会用到。
视频讲解:动态规划之背包问题,装满背包有多少种方法?| LeetCode:494.目标和_哔哩哔哩_bilibili
474.一和零
通过这道题目,大家先粗略了解, 01背包,完全背包,多重背包的区别,不过不用细扣,因为后面 对于 完全背包,多重背包 还有单独讲解。
视频讲解:动态规划之背包问题,装满这个背包最多用多少个物品?| LeetCode:474.一和零_哔哩哔哩_bilibili
题解思路:
这题算是常规的动态规划题目,只不过背包容量要考虑两个维度了,背包容量大小为m个0,n个1,最大能背dp[i][j]个物品
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m+1][n+1]; //默认初始化为0
for(String str : strs){ //遍历每个物品
int x = 0; //记录遍历每个字符串中0的个数
int y = 0; //记录遍历每个字符串中1的个数
for(int i = 0; i < str.length(); i++){
if(str.charAt(i) == '0') x++;
else y++;
}
for(int j = m; j >= x; j--){ //遍历背包容量大小
for(int k = n; k >= y; k--){ //背包容量大小为m个0,n个1,最大能背dp[i][j]个物品
dp[j][k] = Math.max(dp[j][k], dp[j-x][k-y] + 1);
}
}
}
return dp[m][n];
}
}