概述
问题陈述
简单的背包问题包括0-1背包问题和完全背包问题。0-1背包问题指的是在可选择项里面,每项最多选择一次,即选择0或者1次。完全背包问题指的是可选择项里面的每项可以选无数次。
做题套路
两层循环,外层是可选择项的每个选项的遍历,里层是背包容量的遍历。在容量增加的情况下,里层的正向遍历会导致重复选择问题,而反序则保证了每个选择最多选择一次。如果0-1背包中每次选项都存在增加或者减少背包容量,则用next数组记录下一步得到的情况,再装回原来的dp数组。
题目
0-1背包问题:
- 416 分割子集问题
- 474 一和零
- 494 目标和
完全背包问题
- 零钱兑换
- 零钱兑换2
题目代码
416
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % 2 == 1) return false;
int* dp = new int[sum/2+1];
for (int i = 0; i <= sum/2; i++) dp[i] = false;
dp[0] = true;
for (auto num : nums) {
for (int i = sum/2; i >= num; i--) {
dp[i] = dp[i-num] || dp[i];
}
}
return dp[sum/2];
}
};
474
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
int** dp = new int*[m+1];
for (int i = 0; i <= m; i++) {
dp[i] = new int[n+1];
for (int j = 0; j <= n; j++) {
dp[i][j] = 0;
}
}
for (auto str : strs) {
vector<int> nums;
if (mp.count(str))
nums = mp[str];
else nums = getNums(str);
for (int i = m; i >= nums[0]; i--) {
for (int j = n; j >= nums[1]; j--) {
dp[i][j] = max(dp[i][j], dp[i-nums[0]][j-nums[1]]+1);
}
}
}
return dp[m][n];
}
vector<int> getNums(string str) {
int r = 0, c = 0;
for (auto ch : str) {
if (ch == '0') r++;
else if (ch == '1') c++;
}
mp[str] = {r,c};
return {r, c};
}
private:
unordered_map<string, vector<int>> mp; // 不用重复计算字符串的0 1个数
};
494
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
if (S < -1000 || S > 1000) return 0;
int* dp = new int[2001], *next = new int[2001];
for (int i = 0; i < 2001; i++) {
dp[i] = 0;
next[i] = 0;
}
dp[1000] = 1;
for (auto num : nums) {
for (int i = 0; i < 2001; i++) {
if (dp[i]) {
if (i-num >= 0) next[i-num] += dp[i];
if (i+num < 2001) next[i+num] += dp[i];
}
}
for (int i = 0; i < 2001; i++) {
dp[i] = next[i];
next[i] = 0;
}
}
return dp[1000+S];
}
};
322
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int* dp = new int[amount+1];
for (int i = 0; i <= amount; i++) dp[i] = amount+1;
dp[0] = 0;
for (auto coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] = min(dp[i], dp[i-coin]+1);
}
}
return dp[amount] == amount+1 ? -1 : dp[amount];
}
};
零钱兑换2
class Solution {
public:
int change(int amount, vector<int>& coins) {
reverse(coins.begin(), coins.end());
if (amount == 0) return 1;
int* dp = new int[amount+1];
for (int i = 0; i <= amount; i++) dp[i] = 0;
dp[0] = 1;
for (auto coin : coins) {
for (int j = 1; j <= amount; j++) {
if (j >= coin)
dp[j] += dp[j-coin];
}
}
return dp[amount];
}
};
参考:
埋滴忒深的博客
labuladong的公众号
最后
以上就是积极飞机为你收集整理的简单背包问题小结的全部内容,希望文章能够帮你解决简单背包问题小结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复