代码随想录刷题第43天

第一题是最后一块石头的重量IIhttps://leetcode.cn/problems/last-stone-weight-ii/,没啥思路,直接上题解了。本题可以看作将一堆石头尽可能分成两份重量相似的石头,于是问题转化为如何合理取石头,使其装满容量为石头总重量一半的背包,且每个石头只能取一次,这样就变成了一个01背包问题。其中石头的重量与价值相同,均为stones[i]。接下来按照动规五步曲进行分析,dp[j]表示容量为j的背包中可以装的最大重量为dp[j],对于第i块石头,可以取也可以不取,故dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]),初始化dp = 0,先遍历物品,再遍历背包即可。

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = 0;
        for (int i = 0; i < stones.size(); i++){
            sum += stones[i];
        }
        int target = sum/2;
        vector<int> dp(150001,0);
        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]); 
            }
        }
        return sum - dp[target] -dp[target];

    }
};

第二题是目标和https://leetcode.cn/problems/target-sum/description/,可以假设加法总和为x,则减法总和为sum - x,题中指出x- (sum - x) = target,可得x = (target + sum)/2。此时题目转化为要装满容量为x的背包共有几种方法,且每个数的状态只能取一次,再次转化为01背包问题。根据动规五步曲,确定dp[j]表示装满容量为j背包的方法数量为dp[j]。当遍历到元素i时,想知道dp[j]的值,必须先知道背包中去掉numbers[i]时dp数组的值,由此反复,得到dp[j] += dp[j - numbers[i]]。初始化将dp[0] = 1,说实话我不是特别理解。遍历顺序依然是先物品后背包,背包从后往前遍历。

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++){
            sum += nums[i];
        }
        if ((target + sum) % 2 == 1) return 0;
        if (abs(target) > sum) return 0;
        int bagsize = (target + sum) / 2;
        vector<int> dp(bagsize + 1, 0);
        dp[0] = 1;
        for (int i = 0; i < nums.size(); i++){
            for (int j = bagsize; j >= nums[i]; j--){
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[bagsize];

    }
};

事实上该题的二维数组解法更为好懂,将其贴在下面:第三题是一和零https://leetcode.cn/problems/ones-and-zeroes/description/,本题的背包维度有两个:m和n,即如何选取元素使元素满足0、1的个数要求。利用动规五步曲:dp[i][j]为拥有i个0,j个1的元素个数。dp[i][j]可由去掉上一个字符串时dp[i - 0nums][j - 1nums]得出,即dp[i][j] = max(dp[i][j], dp[i - 0nums][j - 1nums] + 1)。由题意可知dp数组初始化为0即可,dp[0][0]=0也符合认知。遍历顺序依然不变。

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
        for (string str : strs){
            int onenum = 0, zeronum = 0;
            for (char c : str){
                if (c == '0') zeronum++;
                else onenum++;
            }
            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);
                }
            }
        }
        return dp[m][n];

    }
};

由此可见,背包问题的维度一般有以下几种:在给定背包容量的情况下,装满背包的最大价值;能否装满;装满背包的方法数量;装满时背包中物品数量;尽可能装满的重量。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值