day 36 第九章 动态规划part04 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

任务日期:7.11

题目一链接:1049. 最后一块石头的重量 II - 力扣(LeetCode)

思路:本题是背包问题解决一定容量的背包里最多能放多少?。本题抽象为有n种物品,将他们尽可能均分成两堆,用容量为sum/2的背包装物品,最后返回包里的和剩余的物品重量的差值即可。

代码:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        //转化为有n种物品,将他们尽可能的均分成两堆,这样差值最小,最后返回两堆的差值;这里就不需要判断sum是奇是偶了,因为这都无所谓,最后算的差值
        vector<int> dp(1501,0);//容量最大是3000,但这里最大的容量是1500就行
        dp[0] = 0;
        int sum = 0;
        for(int i = 0;i < stones.size();i ++) {
            sum += stones[i];
        }
        int target = sum / 2;
        for(int i = 0;i < stones.size();i ++) {
            for(int j = target;j >= stones[i];j --) {
                dp[j] = max(dp[j],dp[j - stones[i]] + stones[i]);//因为dp坐标内是减法,所以前面的dp值会影响后面的值,因此倒序j先算后面的值,不会对前面的值产生影响。
            }
        }

        return sum - dp[target] - dp[target];
    }
};

难点:

解释细节1:背包问题能计算出在一定背包容量下的最大的重量或者最大价值




题目二链接:494. 目标和 - 力扣(LeetCode)

思路:本题抽象为求装满容量为x的背包的方法数。x是数组中正数元素的加和,由两个公式推导出来。

代码:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for(int i = 0;i < nums.size();i ++) {
            sum += nums[i];
        }

        int x = (target + sum) / 2;
        if((target + sum) % 2 != 0) return 0;
        if(abs(target) > sum) return 0;

        vector<int> dp(x + 1,0);//此时的dp[j]代表装满容量为j的背包的方法有多少种
        //dp[j] += dp[j - nums[i]];
        dp[0] = 1;//记住,如果是0的话后面的值都是0
        for(int i = 0;i < nums.size();i ++) {
            for(int j = x;j >= nums[i];j --) {
                //背包问题计算的方法数的公式
                dp[j] += dp[j - nums[i]];
            }
        }

        return dp[x];
    }
};

难点:

解释细节1:dp[j]代表用物品装满j重量的背包的方法数。




题目三链接:474. 一和零 - 力扣(LeetCode)

思路:装满一个背包用的最大物品数。这道题可以抽象为一道背包问题,只是比一般背包问题的容量多了一个维度,这里有两个容量:1的个数和0的个数,同时物品的种类是每段单独的字符串。明白这个后再套用背包问题的模版。

代码:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        //dp[i][j]:i代表0的个数 j代表1的个数
        vector<vector<int>> dp(m + 1,vector<int>(n + 1,0));//全部初始化为零
        //确定递推公式
        //dp[i][j] = max(dp[i][j],dp[i - zeroNum][j - oneNum] + 1);
        for(string str : strs) {//遍历物品:每个字符相当于一个物品
            int oneNum = 0,zeroNum = 0;
            for(char c : str) {
                if(c == '0') zeroNum ++;
                else oneNum ++;
            }

            //遍历背包容量:对0 1 的容量进行遍历
            //递推顺序:容量倒序递推
            for(int i = m;i >= zeroNum;i --) {
                for(int j = n;j >= oneNum;j --) {
                    dp[i][j] = max(dp[i][j],dp[i - zeroNum][j - oneNum] + 1);//选当前的元素的情况:先减去当前元素0的个数再减去1的个数然后dp再加1
                }
            }
        }
        
        return dp[m][n];
    }
};

难点:

解释细节1:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值