1049. 最后一块石头的重量 II
思路与重点
- 本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = accumulate(stones.begin(), stones.end(), 0);
int target;
target = sum / 2;
int dp[1501] = {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];
}
};
494. 目标和
思路与重点
- **回溯法能解决,但时间复杂度太高!**原因是重叠的子问题没有剔除掉。
class Solution {
private:
int ans = 0;
void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {
if (sum == target) {
ans++;
}
for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
sum += candidates[i];
backtracking(candidates, target, sum, i + 1);
sum -= candidates[i];
}
}
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (S > sum) return 0;
if ((S + sum) % 2) return 0;
int bagSize = (S + sum) / 2;
sort(nums.begin(), nums.end());
backtracking(nums, bagSize, 0, 0);
return ans;
}
};
- 先尝试用二维dp的方式进行解决:可以先用简单例子进行模拟,关键是找到递推公式, 不放物品i:即背包容量为j,里面不放物品i,装满有dp[i - 1][j]中方法;放物品i: 即:先空出物品i的容量,背包容量为(j - 物品i容量),放满背包有 dp[i - 1][j - 物品i容量] 种方法。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if(abs(S) > sum) return 0;
if((sum + S) % 2 == 1) return 0;
int bagSize = (sum + S) / 2;
vector<vector<int>> dp(nums.size(), vector<int>(bagSize + 1, 0));
if(nums[0] <= bagSize) dp[0][nums[0]] = 1;
dp[0][0] = 1;
int numZero = 0;
for(int i = 0; i < nums.size(); i++){
if(nums[i] == 0) numZero++;
dp[i][0] = (int) pow(2, numZero);
}
for(int i = 1; i < nums.size(); i++){
for(int j = 0; j <= bagSize; j++){
if(j < nums[i]) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i-1][j] + dp[i-1][j - nums[i]];
}
}
return dp[nums.size() - 1][bagSize];
}
};
- 再简化为一维dp:这里为什么不需要考虑numZero了呢?
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (abs(target) > sum) return 0;
if ((target + sum) % 2 == 1) return 0;
int bagSize = (target + 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];
}
};
474.一和零
思路与重点
- 每个物品只有一个 -> 按01背包解决
- 找出递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 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 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];
}
};