首页 > 编程语言 >算法刷题 Day 43 | ● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

算法刷题 Day 43 | ● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

时间:2023-02-18 21:00:18浏览次数:57  
标签:背包 return target int 1049 43 II sum dp

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

本题就和 昨天的 416. 分割等和子集 很像了,可以尝试先自己思考做一做。

视频讲解:https://www.bilibili.com/video/BV14M411C7oV

https://programmercarl.com/1049.%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E7%9F%B3%E5%A4%B4%E7%9A%84%E9%87%8D%E9%87%8FII.html

Tips:其实只要把石头分成重量尽可能相等的两堆就可以了,所以和昨天的最后一题是一样的思路。

我的题解:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = 0;
        for(int i = 0; i<stones.size();i++){
            sum += stones[i];
        }
        int half = sum / 2;     
        vector<int> dp(half + 1);
        dp[0] = 0;
        // stones数组既是重量也是价值
        for(int i = 0; i<stones.size();i++){
            for(int j = half; j >= stones[i]; j--){
                dp[j] = max(dp[j],dp[j - stones[i]] + stones[i]);
            }
        }
        return (sum - dp[half]) - dp[half];
    }
};

494. 目标和 

大家重点理解 递推公式:dp[j] += dp[j - nums[i]],这个公式后面的提问 我们还会用到。

视频讲解:https://www.bilibili.com/video/BV1o8411j73x

https://programmercarl.com/0494.%E7%9B%AE%E6%A0%87%E5%92%8C.html

Tips:这道题有两个点比较不容易想到

1. 将有正有负的问题,通过加上sum变成只求正的元素,这一步很巧妙

如何转化为01背包问题呢。

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

此时问题就转化为,装满容量为x的背包,有几种方法

这里的x,就是bagSize,也就是我们后面要求的背包容量。

大家看到(target + sum) / 2 应该担心计算的过程中向下取整有没有影响。

这么担心就对了,例如sum 是5,S是2的话其实就是无解的,所以:

(C++代码中,输入的S 就是题目描述的 target)
if ((S + sum) % 2 == 1) return 0; // 此时没有方案

同时如果 S的绝对值已经大于sum,那么也是没有方案的。

(C++代码中,输入的S 就是题目描述的 target)
if (abs(S) > sum) return 0; // 此时没有方案

再回归到01背包问题,为什么是01背包呢?

因为每个物品(题目中的1)只用一次!

这次和之前遇到的背包问题不一样了,之前都是求容量为j的背包,最多能装多少。

本题则是装满有几种方法。其实这就是一个组合问题了。

2. 递推公式有变化。在求装满背包有几种方法的情况下,递推公式一般为:

dp[j] += dp[j - nums[i]];

我的题解:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        // 正的数相加等于 (target + sum) / 2,只需要求有几种组合相加等于这个值即可
        int sum = 0;
        for(int i = 0; i<nums.size(); i++){
            sum+=nums[i];
        }
        if((target + sum)%2 == 1){
            // 如果这个值带0.5的话,是无解的
            return 0;
        }
        if(abs(target) > sum){
            // 如果target大于总和的话,也是无解的
            return 0;
        }
        int positive = (target + sum) / 2;

        vector<int> dp(positive+1,0);
        dp[0] = 1;
        for(int i = 0; i<nums.size(); i++){
            for(int j = positive; j>=nums[i]; j--){
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[positive];
    }
};

474.一和零  

通过这道题目,大家先粗略了解, 01背包,完全背包,多重背包的区别,不过不用细扣,因为后面 对于 完全背包,多重背包 还有单独讲解。

视频讲解:https://www.bilibili.com/video/BV1rW4y1x7ZQ

https://programmercarl.com/0474.%E4%B8%80%E5%92%8C%E9%9B%B6.html

Tips:这道题还是01背包的思路,唯一区别就是背包有两个袋子,一个装0,一个装1而已。

我的题解:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));

        for(int i = 0; i<strs.size(); i++){
            int num0 = 0;
            int num1 = 0;
            for(int j = 0; j<strs[i].size(); j++){
                if(strs[i][j] == '0'){
                    num0++;
                }
                else{
                    num1++;
                }
            }

            for(int j = m; j>=num0;j--){
                for(int k = n; k>=num1; k--){
                    dp[j][k] = max(dp[j][k],dp[j-num0][k-num1]+1);
                }
            }
        }

        return dp[m][n];
    }
};

标签:背包,return,target,int,1049,43,II,sum,dp
From: https://www.cnblogs.com/GavinGYM/p/17133593.html

相关文章