随想录一刷Day43——动态规划

Day43_动态规划

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

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

要让最后剩下的石头的重量最小,即消磨得石头的重量越多,即让重量尽可能接近的石头两两相碰。于是可以统计石头的总重量sum,将问题转化为,在容量为sum/2的背包中放入尽可能重的石头,这样背包中的石头与没有装入背包的石头互相碰撞,最后一定能消磨到只剩 sum - dp[target] - dp[target] 的重量。
粗糙证明一下结论正确性,如果没有将背包中装入最大的重量,一定有石头本可以装入背包而没有装入背包,那么消磨掉背包中的石头后,没有装入背包的石头还需要彼此消磨,直到把本可以装进去却没装进去的部分消磨掉,相当于装进了背包,所以上述方法是正确的。

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

15. 目标和

494. 目标和
思路:

  1. dp[j] 表示填满容量 j 的种类数
  2. d p [ j ] = ∑ d p [ j − n u m s [ i ] ] dp[j] = \sum{dp[j - nums[i]]} dp[j]=dp[jnums[i]]
  3. 初始化 dp[0] = 1 ,填满容量 0 的方法数有一种,就是不填
  4. 外层循环遍历整个nums[]数组,内层循环倒序遍历背包容量,因为扩展到二维用的是上一行的处理结果,从前往后的话会更新前面的结果,导致后面的计算出错。

nums中正数相加的和为 positive_sum
则有 positive - (sum - positive) = target
将问题转化为求整数之和为 positive_sum = (sum + target) / 2 的方法数,使用 01 背包,求容量为 positive_sum 的背包被装满的方法数

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

17. 一和零

474. 一和零
思路:

经典 01 背包,只不过容量分两维,0的容量一维,1的容量一维。每个字符串带来的价值是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 (string str : strs) {
            int ZeroNum = 0, OneNum = 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];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值