代码随想录算法训练营第四十二天|1049. 最后一块石头的重量 II 494. 目标和 474.一和零

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

题目链接:1049. 最后一块石头的重量 II

踩坑:最后的返回值应该是sum减去已经凑出来的石头堆两次。

思路:关键在于认识到不止两个石头的差可以得到,两堆石头的差也能得到。所以题目可以变成将这一堆石头分成两堆重量相似的石头。求解过程就变成了分割等和子集

代码:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = accumulate(stones.begin(), stones.end(), 0);
        int target = sum/2;
        vector<int> dp(target+1, 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];
    }
};

LeetCode 494. 目标和

题目链接:494. 目标和

踩坑:装满背包的总方法数那里绕了点

思路:核心是将所有元素分成正数和负数两组,正数+负数=target,正数-负数=sum,以此可以求出正数的总和,也即背包的大小。

  1. 动态数组的含义:dp[j]:装满大小为 j 的背包一共有多少种方法
  2. 递推公式:dp[j] = dp[j] + dp[j - weight[i]]。注意,等号左边的dp[j]是新的,右边的dp[j]是旧的,表示的是如果不放入当前物品装满 j 的背包有多少种方法,dp[j - weight[i]]表示放入当前物品将 j 的背包装满有多少种方法
  3. 初始化动态数组:dp[0] = 1。当target为0,数组为{0}时,代入公式得正数=0,有解
  4. 遍历顺序:先物品再背包

代码:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = accumulate(nums.begin(), nums.end(), 0);
        if((sum + target) % 2) return 0;
        int bagsize = (sum+target)/2;
        if(bagsize < 0) return 0;
        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] + dp[j-nums[i]]; 
            }
        }
    return dp[bagsize];
    }
};

LeetCode 474.一和零

题目链接:474.一和零

踩坑:对于有两个维度的物品的背包问题不熟悉。误解了题意,理解成满足最多m个0,n个1的子集有多少种了,应该是满足要求的最大子集。

思路:

  1. dp数组含义:dp[i][j]:最多i个0,j个1的子集的最大长度
  2. 递推公式:dp[i][j] = max(dp[i][j], dp[i - x][j - y]+1)
  3. 初始化:dp[0][0] = 0,其他也都是0
  4. 遍历顺序:物品正向,背包反向

代码:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
        dp[0][0] = 0;
        for(string str: strs)
        {
            int x = 0, y = 0;
            for(char s: str)
            {
                if(s == '0') x++;
                if(s == '1') y++;
            }
            for(int i = m; i >= x; i--)
            {
                for(int j = n; j >= y; j--)
                {
                    dp[i][j] = max(dp[i][j], dp[i-x][j-y]+1);
                }
            }
        }
        return dp[m][n];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值