代码随想录算法训练营day43 | 1049. 最后一块石头的重量 II ,494. 目标和,474.一和零,01背包问题总结

代码随想录算法训练营day43 | 1049. 最后一块石头的重量 II ,494. 目标和,474.一和零


1049. 最后一块石头的重量 II

教程视频:https://www.bilibili.com/video/BV14M411C7oV
在这里插入图片描述

思路:尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就将本题化解成01背包问题了。
此时背包容量是sum/2,物品重量和价值都等于数组中的每个数字。

解法一:动态规划

1、dp[j]含义:将数值放入容量为j的背包中能得到的最大重量。
2、递推公式:dp[j]=Math.max(dp[j], dp[j-stones[i]]+stones[i]);
3、dp初始化:dp[0]=0;重量都大于等于1,为正整数,递推过程中小的值会被覆盖,因此其他索引的值初始化成0就可以
4、遍历顺序:外层for控制放入被报道石头,内层for反向遍历背包容量
5、打印验证

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for(int i=0;i<stones.length;i++){
            sum +=stones[i];
        }
        //创建dp数组
        int bagSize = sum/2;
        int[] dp = new int[bagSize+1];
        //java默认初始化为0,不需要显示初始化

        for(int i=0;i<stones.length;i++){
            for(int j=bagSize;j>=stones[i];j--){
                //两种情况,要么放,要么不放
                dp[j] = Math.max(dp[j],dp[j-stones[i]]+stones[i]);
            }
        }
        return sum-2*dp[bagSize];
    }
}

494. 目标和

教程视频:https://www.bilibili.com/video/BV1o8411j73x
在这里插入图片描述
在这里插入图片描述
思路:将所有数值划分为加的数(positive)和减的数(negative),sum=positive+negative,根据题意需要满足positive-negative=target。可以转换成:positive-(sum-positive)=target,由于sum和target已知,positive=(sum+target)/2,这就是背包容量。如果positive不为整数,说明nums不能凑成target(可以剪枝)。

解法一:动态规划

1、dp[j]定义:和为j的表达式数目。
2、递推公式:dp[j]+=dp[j-nums[i]];(只要搞到nums[i],就有dp[j - nums[i]] 种方法可以凑成dp[j]。
3、dp初始化:因为递推公式是累加,dp[0]不能为0,可以想成和为0就只有所有值都不放入背包这一种方式,dp[0]=1;其他都是加法累计过来的,初始化为0。
4、遍历顺序:外层for遍历nums,内层for倒序遍历背包容量。
5、打印验证。

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum=0;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
        }
        //如果target绝对值大于sum,将无法满足,返回0
        if( target > sum)return 0;
        if ( target < 0 && sum < -target) return 0;

        //如果sum+target/2为小数,将不能得到target,返回0
        if((sum+target)%2 == 1)return 0;
        int bagSize = (sum+target)/2;//经过上面的判断,bagSize一定大于等于0
        
        int[] dp = new int[bagSize+1];
        dp[0]=1;
        for(int i=0;i<nums.length;i++){
            for(int j=bagSize;j>=nums[i];j--){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[bagSize];
    }
}

474.一和零

教程视频:https://www.bilibili.com/video/BV1rW4y1x7ZQ
在这里插入图片描述
思路:本题类似1049. 最后一块石头的重量 II,但是本题的背包容量有两个维度(可以理解为从重量和体积两个维度限制了放入为物品),因此背包需要使用两层for循环来反向遍历。

解法一:动态规划

1、dp[j][k]含义:背包容量为 j 个0和 k个1时,最大子集长度。
2、递推公式:dp[j][k]=Math.max(dp[j][k], dp[j-a][k-b]+1);其中 a为strs中0的个数,b为strs中1的个数。
3、dp初始化:dp[0][0]=0;,对于其他非0下标,都会被max迭代,所以取最小值0即可。
4、遍历顺序:外层for循环遍历strs,内层两个for循环倒序遍历背包容量。
5、打印验证

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        //创建dp数组,dp[j][k]表示j个0和k个1时的最大子集
        int[][] dp = new int[m+1][n+1];
        //初始化dp数组,默认为0,无需显示初始化

        for(int i=0;i<strs.length;i++){
            //统计strs[i]中0和1的个数
            int a=0,b=0;
            for(int index=0;index<strs[i].length();index++){
                if(strs[i].charAt(index)=='0'){
                    a++;
                }else{
                    b++;
                }
            }
            // System.out.println(strs[i]+"中,0的个数="+a+", 1的个数="+b);
            for(int j=m;j>=a;j--){
                for(int k=n;k>=b;k--){
                    dp[j][k]=Math.max(dp[j][k], dp[j-a][k-b]+1);
                }
            }
        }
        return dp[m][n];
    }
}

01背包问题总结

此时我们讲解了0-1背包的多种应用,

  • 纯 0 - 1 背包 是求 给定背包容量 装满背包 的最大价值是多少。dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);输出dp[dp.length-1];
  • 416.分割等和子集是求 给定背包容量,能不能装满这个背包。dp[j]=Math.max(dp[j], dp[j-nums[i]]+nums[i]);输出dp[sum/2] == sum/2;
  • 1049.最后一块石头的重量 II是求 给定背包容量,尽可能装,最多能装多少。dp[j]=Math.max(dp[j], dp[j-stones[i]]+stones[i]);输出sum-2*dp[bagSize];
  • 494.目标和 是求 给定背包容量,装满背包有多少种方法。dp[j]+=dp[j-nums[i]];输出dp[bagSize];
  • 474.一和零 是求 给定背包容量,装满背包最多有多少个物品。dp[j][k]=Math.max(dp[j][k], dp[j-a][k-b]+1);输出dp[m][n];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值