01背包问题做题总结(二)

目标和

这道题和之前的不太一样,乍一看可以拿组合总和问题一样,想尝试回溯法,发现超时,于是我们可以用动态规划,这时我们要考虑dp数组的定义是什么

我们假设加法的和为x,那减法的和就是sum-x,可以推出x-(sum-x) = target,举个例子,以示例1为例,tar=3,加法和为2的话,一减,减法和就是1,所以x要减(sum-x)才是target,这里要注意,不是加,还有就是nums都要参与运算,不是取几个构造也要注意,可以推出x = (sum+target)/2;x为背包容量,所以dp的定义为填满容量为x的背包有几种方法,此时有人考虑到x会不会向下取整,对的,所以如果(sum + target)%2!=0,返回0。
递推公式:举个例子,dp[4] 有几个,我们首先要拿到一个数比如我们拿到nums[0]=1,那么我们只
需求dp[3]即可,dp[3]有几个,dp[4]由他们加上1得来,再拿一个数为2,dp[4]再加上dp[1]的个数即可
所以递推公式为:dp[j] += dp[j - nums[i]];
初始化:dp都由dp[0]推导而来,dp[0]必须为1,不然递归都是0,很好理解,填满容量为0的背包
有两种方法,就是放0件物品
遍历顺序先遍历物品,背包容量大到小

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int n = nums.length;
        int sum = 0;
        for(int i = 0;i < n;i++) {sum += nums[i];}
        int bag = (sum + target) / 2;
        if(Math.abs(target) > sum) {return 0;}
        if((sum + target) % 2 ==1){return 0;}
        int[] dp = new int[bag + 1];
        dp[0] = 1;
        for(int i = 0;i < n;i++) {
            for(int j = bag;j >= nums[i];j--) {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[bag];
    }
}

1和0

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        //这道题其实是一个01背包问题,因为strs相当于物品,每个字符串都是一个物品,每个物品都只有一个
        //而m,n相当于背包,只不过这个背包有两个维度而已,理解了题意,那这道题就可以开始做了
        //dp数组的定义,dp[i][j],表示最多有i个0,j个1的strs的子集最大长度
        //递推公式:定义0的个数numOf0,1的个数numOf1,dp[i][j] 由dp[i - numOf0][j - numOf1] + 1和
        //它本身比大小得来,这里的意思是,举个例子,循环拿物品,我拿了”10“,有1个0,1个1,我们之后的
        //dp都带上这个物品一起玩,把它的个数减掉求到的dp的值加上它本身的长度1,再和之前一比,谁大,那新的dp[i][j]就是谁,循环遍历strs,得到的dp[m][n]就是最长的子集
        //所以dp[i][j] = Math.max(dp[i][j],dp[i - numOf0][j - numOf1] + 1);
        //初始化:0即可
        //遍历顺序:
        int[][] dp = new int[m + 1][n + 1];
        for(String string:strs) {
            int numOf0 = 0;
            int numOf1 = 0;
            for(int i = 0;i < string.length();i++) {
                if(string.charAt(i)=='0') numOf0++;
                else numOf1++;
            }
            for(int i = m;i >= numOf0;i--) {
                for(int j = n;j >= numOf1;j--) {
                    dp[i][j] = Math.max(dp[i][j],dp[i - numOf0][j - numOf1] + 1);
                }
            }
        }
        return dp[m][n];
    }
}

这两道题还是很难的,有些同学可能觉得写出递推公式就行了,其实递推公式只是一小部分,你需要理解dp数组的定义,初始化,遍历的顺序,我觉得最重要的是怎样理解题意,把题转换成背包的格式,什么当作物品,什么是背包,再根据物品数量的特性决定是01背包,还是完全背包,还是别的,理解比什么都重要,剩下的就是多练习找感觉了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值