Day73(动态规划——01背包应用问题)

以下三题包含了01背包算法的三种题型:

①存在问题(力扣416)

②最值问题(力扣474)

③组合问题(力扣494)

416、分割等和子集——01背包的存在问题(存在问题返回索引为背包容量的元素)

给你一个 只包含正整数 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

因为题目是存在问题、又是背包的解法,所以我们只要算出背包容量、物品重量就行了。不需要判断物品的价值是什么 

根据题目可得:该背包的容量为Sum(nums)/2、物品重量:nums[i]、(不需要判断:物品价值:nums[i]

一维数组的解法:

class Solution {
    public boolean canPartition(int[] nums) {
        //根据题目可得:该背包的容量为Sum(nums)/2、物品价值:nums[i]、物品重量:nums[i] 
        int sum=0;
        for(int num:nums){
            sum+=num;
        }
        //总和为奇数,肯定不能平分为2个背包
        if(sum%2!=0) return false;

        int target=sum/2; //背包的容量
        boolean []dp=new boolean[target+1];//容量为j的背包,最大价值为dp[j]
        dp[0]=true;//初始化:target=0不需要选择任何元素,所以是可以实现的

        //遍历顺序:先遍历物品,再遍历容量,且遍历容量是倒序遍历
        for(int i=0;i<nums.length;i++){
            //容量要大于物品的重量
            for(int j=target;j>=nums[i];j--){
                dp[j]=dp[j]||dp[j-nums[i]];
            }
        }
        return dp[target];
    }
}

 474、一和零——01背包的最值问题(最值问题返回索引为题目给的形参的元素)

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

首先考虑到背包问题之后,先明确背包的容量、物品的价值、物品的重量

两个背包的容量分别是m和n    

物品的价值:字符串本身的个数即1    

物品重量:zeroNums和oneNums

因为我们是两个背包的容量,所以我们可以设置为三维数组,dp[i][j][k]

我们还可以进行滚动数组的做法,将三维数组压缩至二维数组,就只要定义二维数组的两个背包的容量就行。 

此题的意思是在遍历每一个字符串中,计算这个字符串的0和1的个数,再进行0-1背包的算法

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        //两个背包的容量分别是m和n    物品的价值:字符串本身的个数即1    物品重量:zeroNums和oneNums
        
        int [][]dp=new int[m+1][n+1];
        //有两个容量0和1,所以我们利用二维的滚动数组来压缩

        //dp[i][j]:表示字符串使用i个0,j个1后获得的最大子集数目

        //记录字符串数组里的每一个字符串的0、1个数
        int zeroNums,oneNums;
        for (String str : strs) {
            zeroNums=0;
            oneNums=0;
            for (char ch : str.toCharArray()) {
                if (ch == '0') {
                    zeroNums++;
                } else {
                    oneNums++;
                }
            }

            //有两个背包的容量——>一定是倒序遍历——>因为我们是利用压缩
            for (int i = m; i >= zeroNums; i--) {
                for (int j = n; j >= oneNums; j--) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeroNums][j - oneNums] + 1);
                }
            }
        }

        return dp[m][n];
    }

}

494、目标和——01背包的组合问题(组合问题返回索引为背包容量的元素)

很详细的转化为【0-1背包】问题的思路 - 目标和 - 力扣(LeetCode) (leetcode-cn.com)

 01背包问题是选或者不选,但本题是必须选,是选+还是选-。先将本问题转换为01背包问题。

 因为都是数组的值都是正整数,所以target绝对值小于等于Sum(nums),所以bagsize一定大于等于0, 所以bagsize小于0与题目条件违背,可以直接返回0种方法

class Solution{
    public int findTargetSumWays(int[] nums, int target){
        int sum=0;
        for(int num:nums){
            sum+=num;
        }
        
        int bagSize=(sum+target)/2;
        if((sum+target)%2!=0||sum<target||bagSize<0) return 0;
        //因为都是数组的值都是正整数,所以target绝对值小于等于Sum(nums),所以bagsize一定大于等于0,所以bagsize小于0与题目条件违背,可以直接返回0种方法
        

        int []dp=new int[bagSize+1];//dp[i]:背包容量为i时,有多少种方式将背包装满
        dp[0]=1;//装满容量为0的背包,有1种方法,就是装0件物品。

        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];//组合问题返回索引为背包容量的元素
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值