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

1049.最后一块石头的重量

题目链接 文章讲解 视频讲解

解题思路:
  将石头尽量分为相等的两堆,两堆最差即为所求结果
  石头的重量就是石头的价值

动规五部曲:

  • dp[j]:表示背包容量为j时可以装的石头的总价值
  • 递推公式:dp[j] = max(dp[j], dp[j-stones[i]] + stones[i]
  • 初始化:均初始化为0
  • 遍历顺序:先遍历石头后遍历背包
  • 打印dp数组
class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int weight = 0;
        for(int val : stones) weight += val;
        int capcity = weight / 2;

        // dp[j] 表示容量为j的背包装的石头的总价值最大为多少
        vector<int> dp(capcity + 1);
        for(int j = 0; j <= capcity; ++j) dp[j] = 0;

        // 递推公式: dp[j] = max(dp[j], dp[j-weight[i]] + value[i])

        // 初始化:均初始化为0
        for(int j = 0; j < capcity; ++j) dp[j] = 0;

        // 先遍历石头后遍历背包
        for(int i = 0; i < stones.size(); ++i) {
            for(int j = capcity; j >= stones[i]; --j) {
                dp[j] = max(dp[j], dp[j-stones[i]] + stones[i]);
            }
        }
        return weight - (dp[capcity] << 1);

    }
};

494.目标和

题目链接 文章讲解 视频讲解

思路:将数组分为两个集合left全部存整数,target全部存负数
那么满足:left + right = sum; left - right = target;
计算得left = (sum + target) / 2;
left即为背包的容量

动规五部曲:

  • dp[j]:装满容量为j的背包有dp[j]种方法
  • 递推公式:dp[j] += dp[j - nums[i]]
  • 初始化:dp[0] = 1, 其他初始化为0
  • 遍历顺序:先遍历物品后遍历背包,背包倒序遍历
  • 打印dp数组
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for(int val : nums) sum += val;
        if((sum + target) % 2 == 1) return 0;
        if(abs(target) > sum) return 0;
        int left = (sum + target) >> 1;

        // dp[j]: 表示容量为j的背包装哪些数可以正好装满
        vector<int> dp(left + 1, 0);

        // 递推公式: dp[j] = dp[j], dp[j - nums[i]] + nums[i];
        // 初始化
        dp[0] = 1;

        for(int i = 0; i < nums.size(); ++i) {
            for(int j = left; j >= nums[i]; --j) {
                dp[j] += dp[j - nums[i]];
            }
        }
        for(int val : dp) cout << val << " ";
        return dp[left];
    }
};

474.一和零

题目链接 文章讲解 视频讲解

  • dp[i][j]: 表示装满i个0和j个1最多可以装dp[i][j]个物品
  • 递推公式:dp[i][j] = max(dp[i - x][j - y], dp[i][j])
  • 初始化:均初始化为0
  • 遍历顺序:先遍历物品后遍历背包
  • 打印dp数组
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 - x][j - y] + 1, dp[i][j])

        // 初始化 dp[i][j] = 0
        
        // 遍历顺序,先遍历物品后遍历背包
        for(string str : strs) {
            int x = 0, y = 0;
            for(char ch : str) {
                if(ch == '0') ++x;
                else ++y;
            }

            // 遍历背包
            for(int i = m; i >= x; --i) { 
                for(int j = n; j >= y; --j) dp[i][j] = max(dp[i - x][j - y] + 1, dp[i][j]);
            }
        }
        return dp[m][n];
    }   
};
posted @ 2024-07-01 14:24  深蓝von  阅读(1)  评论(0编辑  收藏  举报