【算法训练营day43】LeetCode1049. 最后一块石头的重量II LeetCode494. 目标和 LeetCode474. 一和零
LeetCode1049. 最后一块石头的重量II
题目链接:1049. 最后一块石头的重量II
独上高楼,望尽天涯路
一开始还是没有想到怎么转化成01背包问题,所以直接看题解找思路
慕然回首,灯火阑珊处
本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。
class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        if (stones.size() == 1) return stones[0];
        int sum_stones = 0;
        for (int stone : stones) {
            sum_stones += stone;
        }
        int bag_weight = sum_stones / 2;
        vector<int> dp(bag_weight + 1, 0);
        for (int i = 0; i < stones.size(); i++) {
            for (int j = bag_weight; j >= stones[i]; j--) {
                dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);
            }
        }
        return sum_stones - 2 * dp[bag_weight];
    }
};
LeetCode494. 目标和
题目链接:494. 目标和
独上高楼,望尽天涯路
卡在这个问题上好几天了,看了题解的递推公式也没有想明白。
慕然回首,灯火阑珊处
首先应该想到的是如何转化成背包问题。
如何转化为01背包问题呢
假设加法的总和为x,那么减法对应的总和就是sum - x
所以我们要求的是 x - (sum - x) = target
x = (target + sum) / 2
此时问题就转化为,装满容量为x的背包,有几种方法
dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
递推公式用二维dp数组表示出来更容易理解,和之前背包问题的思路一样,无非是对于第i件物品有放进背包和不放进背包两种情况,现在要统计的是装满背包一共有多少种方法,只需要将这两种情况的方法数加起来,就是考虑0到i物品的总方法数,即dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]],化简为一维dp数组滚动表示后才是代码中的递推公式。
最后考虑一维dp数组的初始化,首先dp[0]一定要是1,可以理解为对于没有空间的背包,本身也是一种装满的状态,如果dp[0]不是1的话,dp数组后面所有的元素就都为0了。
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum_nums = 0;
        for (int i = 0; i < nums.size(); i++) sum_nums += nums[i];
        if ((target + sum_nums) % 2 == 1) return 0;
        if (abs(target) > sum_nums) return 0;
        int bag_size = (target + sum_nums) / 2;
        vector<int> dp(bag_size + 1, 0);
        dp[0] = 1;
        for (int i = 0; i < nums.size(); i++) {
            for (int j = bag_size; j >= nums[i]; j--) {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[bag_size];
    }
};
LeetCode474. 一和零
题目链接:474. 一和零
独上高楼,望尽天涯路
本题不过是一个二维空间的01背包,用经典的解法即可。
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 zeros = 0;
            int ones = 0;
            for (int l = 0; l < strs[i].size(); l++) {
                if (strs[i][l] == '0') zeros++;
                else ones++;
            }
            for (int j = m; j >= zeros; j--) {
                for (int k = n; k >= ones; k--) {
                    dp[j][k] = max(dp[j][k], dp[j - zeros][k - ones] + 1);
                }
            }
        }
        return dp[m][n];
    }
};
慕然回首,灯火阑珊处
思路完全一样。
本题中strs 数组里的元素就是物品,每个物品都是一个!
而m 和 n相当于是一个背包,两个维度的背包。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号