bash
第九章 动态规划 part05
● 1049. 最后一块石头的重量 II
● 494. 目标和
● 474.一和零
详细布置
1049. 最后一块石头的重量 II
本题就和 昨天的 416. 分割等和子集 很像了,可以尝试先自己思考做一做。
视频讲解:https://www.bilibili.com/video/BV14M411C7oV
https://programmercarl.com/1049.%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E7%9F%B3%E5%A4%B4%E7%9A%84%E9%87%8D%E9%87%8FII.html
494. 目标和
大家重点理解 递推公式:dp[j] += dp[j - nums[i]],这个公式后面的提问 我们还会用到。
视频讲解:https://www.bilibili.com/video/BV1o8411j73x
https://programmercarl.com/0494.%E7%9B%AE%E6%A0%87%E5%92%8C.html
474.一和零
通过这道题目,大家先粗略了解, 01背包,完全背包,多重背包的区别,不过不用细扣,因为后面 对于 完全背包,多重背包 还有单独讲解。
视频讲解:https://www.bilibili.com/video/BV1rW4y1x7ZQ
https://programmercarl.com/0474.%E4%B8%80%E5%92%8C%E9%9B%B6.html
day42
最后一块石头的重量2
//把石头分成重量相近的两堆,然后一边取一个放进去磨,左边石头磨完了再从左边取一个放进去和右边磨过的石头一起磨,这样最后剩下的时候头就是abs(左堆重量- 右堆重量)
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 = stones[0]; i <= target; i++){//这里i = target也需要初始化
// dp[i] = stones[0];
//}
//for( int i = 1; i < stones.length ; i++){
for( int i = 0; i < stones.length ; i++){//对一维来说,第一行的初始化可以放进循环,因为不涉及dp[i - 1][j],所以i可以为0
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];
}
}
目标和
dp[i][j]
表示用0~i号元素装满容量j,的方法,的个数
//为了理解一维数组,在idea中的调试代码
class demo02 {
public static void main(String[] args) {
int[] nums = {0,0,0};
int target = 0;
findTargetSumWays(nums,target);
}
public static int findTargetSumWays(int[] nums, int target) {
//分成两组left和right,left - right = target即可,又因为left+right = sum,消去right,left = (sum + target)/2
//dp[i][j]表示从物品0到i去选,能组成容量j的 方法 有多少种
//不放物品i和放物品i两种情况推出来:dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]](也就是留出放j的空间去)
int sum = 0;
for(int i : nums){
sum += i;
}
if((sum + target ) % 2 != 0) return 0;
if( sum < Math.abs(target) ) return 0;
int bagweight = sum + target >> 1;
int[][] dp = new int[nums.length][bagweight + 1];
//初始化
//第一行,只有nums[0] == j的时候,以及j == 0的时候,为1,其他都为0
//我们把dp[0][0]留给列去初始化,因为nums[0]是0的时候dp[0][0]是2
//对于一维数组来说,他的第一行初始化可以自己赋值,dp[0][0]是1还是2,也可以直接交给for里面i=0,但是初始化之前依然要把dp[0]赋值为0
//这是因为相当于是从[1,0,0,0]去初始化的i = 0这一行,如果第一个nums[0]==0,i=0那一行就是[2,0,0,0]
//一维数组可以避免非常麻烦的初始化
if(nums[0] <= bagweight) dp[0][nums[0]] = 1;//记得数组下标都需要判断一下
//第一列,什么都不放这一种方法,或者数组里面有0
//for(int i = 0; i < nums.length; i++){//这个初始化忽略了数组中可能有0的情况
// dp[i][0] = 1;
//}
int numZeros = 0;
for(int i = 0; i < nums.length; i++) {
if(nums[i] == 0) {
numZeros++;
}
dp[i][0] = (int) Math.pow(2, numZeros);
}
//for(int i = 0; i < nums.length; i++){//这个初始化忽略了数组中可能有0的情况
// dp[i][0] = 1;
//}
for(int i = 1; i < nums.length ; i++) {
for (int j = 1; j <= bagweight; j++) {
if (j < nums[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]];
}
}
printall(dp);
return dp[nums.length - 1][bagweight];
}
public static void printall(int[][] dp){
int numslength = dp.length;
int weight = dp[0].length;
for(int i = 0; i < numslength ; i++) {
for (int j = 0; j < weight; j++) {
System.out.print(dp[i][j]);
System.out.print(" ");
}
System.out.println();
}
}
}
一和零
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
//背包有两个容量mn
int[][] dp = new int[m+1][n+1];
//初始化都为0
//先遍历物品再遍历背包
for( String str : strs){
int x = 0;
int y = 0;
for(char ch : str.toCharArray()){
if(ch == '0') x++;
else y++;
}
for(int i = m; i >= x; i--){
for(int j = n; j >=y; j--){
dp[i][j] = Math.max( dp[i][j], dp[i-x][j-y] + 1);
}
}
}
return dp[m][n];
}
}
感谢大佬分享: