提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、1049最后一块石头的重量 II
思路:把石头尽可能分成两堆,让两堆石头重量尽可能相近。
二维dp:
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int target = 0;
for (int stone: stones) {
target += stone;
}
vector<vector<int>> dp(stones.size(), vector<int>(target / 2 + 1, 0));
for (int j = stones[0]; j <= target / 2; j ++) {
dp[0][j] = stones[0];
}
int maxWeight = 0;
for (int i = 1; i < stones.size(); i ++) {
for (int j = 1; j <= target / 2; j ++) {
dp[i][j] = dp[i-1][j];
if (j >= stones[i]) {
dp[i][j] = max(dp[i-1][j-stones[i]] + stones[i], dp[i][j]);
}
maxWeight = max(maxWeight, dp[i][j]);
}
}
int otherWeight = target - maxWeight;
return abs(maxWeight - otherWeight);
}
};
一维dp:
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int target = 0;
for (int stone: stones) {
target += stone;
}
vector<int> dp(target / 2 + 1, 0);
for (int i = 0; i < stones.size(); i ++) {
for (int j = target / 2; j >= stones[i]; j --) {
dp[j] = max(dp[j], dp[j-stones[i]] + stones[i]);
}
}
return target - 2 * dp[target/2];
}
};
二、494目标和
二维dp:
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
//left + right = sum
//right = sum - left
//left - right = target
//left - (sum - left) = target
//left = (target + sum) / 2
int sumNum = 0;
for (int num: nums) {
sumNum += num;
}
if (target * -1 > sumNum) {
return 0;
}
if ((target + sumNum) % 2 == 1) {
return 0;
}
target = (target + sumNum) / 2;
vector<vector<int>> dp(nums.size(), vector<int>(target + 1, 0));
//dp[i][j]:有多少种方式能把这个容量为j的背包装满
for (int j = 1; j < target + 1; j ++) {
if (j == nums[0]) {
dp[0][j] = 1;
}
}
int countZeros = 0;
for (int i = 0; i < nums.size(); i ++) {
if (nums[i] == 0) {
countZeros ++;
}
dp[i][0] = pow(2, countZeros);
}
for (int i = 1; i < nums.size(); i ++) {
for (int j = 1; j < target + 1; j ++) {
dp[i][j] = dp[i-1][j];
if (j >= nums[i]) {
dp[i][j] += dp[i-1][j-nums[i]];
}
}
}
return dp[nums.size()-1][target];
}
};
一维dp:
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sumNum = 0;
for (int num: nums) {
sumNum += num;
}
if ((target + sumNum) % 2 == 1 || abs(target) > abs(sumNum)) {
return 0;
}
int left = (target + sumNum) / 2;
vector<int>dp(left + 1, 0);
int countZeros = 0;
if (nums[0] == 0) {
countZeros ++;
}
dp[0] = pow(2, countZeros);
for (int j = 1; j < left + 1; j ++) {
if (nums[0] == j) {
dp[j] = 1;
}
}
for (int i = 1; i < nums.size(); i ++) {
if (nums[i] == 0) {
countZeros ++;
}
for (int j = left; j > 0; j --) {
if (j >= nums[i]) {
dp[j] += dp[j-nums[i]];
}
}
dp[0] = pow(2, countZeros);
}
return dp[left];
}
};
优化版:一维dp不需要初始化那么多,初始化第一个元素即可。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sumNum = 0;
for (int num: nums) {
sumNum += num;
}
if ((target + sumNum) % 2 == 1 || abs(target) > abs(sumNum)) {
return 0;
}
int left = (target + sumNum) / 2;
vector<int>dp(left + 1, 0);
dp[0] = 1;
for (int i = 0; i < nums.size(); i ++) {
for (int j = left; j >= 0; j --) {
if (j >= nums[i]) {
dp[j] += dp[j-nums[i]];
}
}
}
return dp[left];
}
};
三、474一和零
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
for (int k = 0; k < strs.size(); k ++) {
int zeros = 0, ones = 0;
for (auto ch: strs[k]) {
if (ch == '0') zeros ++;
else ones ++;
}
for (int i = n; i >= ones; i --) {
for (int j = m; j >= zeros; j --) {
dp[i][j] = max(dp[i][j], 1 + dp[i-ones][j-zeros]);
}
}
}
return dp[n][m];
}
};