leetcode1049:最后一块石头的重量2
文章讲解:leetcode1049
leetcode494:目标和
文章讲解:leetcode494
leetcode474:1和0
文章讲解:leetcode474
目录
1,leetcode1049 最后一块石头的重量2
按照我的理解,这道题是需要将石头分为重量接近的两堆,这样两两消除后剩下的重量就是最小的。背包的重量就是stone,价值也是stone;
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int dp[15001] = {0};
int sum = 0;
for(int&x: stones){
sum += x;
}
int target = sum/2;
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];
}
};
看出来是个01背包问题,
dp[j]表示容量(这里说容量更形象,其实就是重量)为j的背包,最多可以背最大重量为dp[j]。
可以回忆一下01背包中,dp[j]的含义,容量为j的背包,最多可以装的价值为 dp[j]。
相对于 01背包,本题中,石头的重量是 stones[i],石头的价值也是 stones[i] ,可以 “最多可以装的价值为 dp[j]” == “最多可以背的重量为dp[j]”
但是对递推过程有些不熟悉。
2,leetcode494 目标和
没啥思路
假设加法的总和为x,那么减法对应的总和就是sum - x。
所以我们要求的是 x - (sum - x) = target
x = (target + sum) / 2
此时问题就转化为,装满容量为x的背包,有几种方法。
所以求组合类问题的公式,都是类似这种:
dp[j] += dp[j - nums[i]]
求装满背包有多少方案的问题都是这个递推式
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (abs(S) > sum) return 0;
if ((S + sum) % 2 == 1) return 0;
int bagSize = (S + sum) / 2;
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 - nums[i]];
}
}
return dp[bagSize];
}
};
3,leetcode474 1和0
本题中strs 数组里的元素就是物品,每个物品都是一个!
而m 和 n相当于是一个背包,两个维度的背包。
理解成多重背包的同学主要是把m和n混淆为物品了,感觉这是不同数量的物品,所以以为是多重背包。
但本题其实是01背包问题!
只不过这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品。
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0)); // 默认初始化0
for (string str : strs) { // 遍历物品
int oneNum = 0, zeroNum = 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-1背包的多种应用,
- 纯 0 - 1 背包是求 给定背包容量 装满背包 的最大价值是多少。
- 416. 分割等和子集是求 给定背包容量,能不能装满这个背包。
- 1049. 最后一块石头的重量 II是求 给定背包容量,尽可能装,最多能装多少
- 494. 目标和是求 给定背包容量,装满背包有多少种方法。
- 本题是求 给定背包容量,装满背包最多有多少个物品。
感觉难的地方还是看出来是个01背包问题。