01背包
不带价值的01背包,求最优解
92. 背包问题
解法1:背包型DP
class Solution {
public:
int backPack(int m, vector<int> &a) {
int n = a.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
// initial
// dp[0][0 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j >= a[i - 1]) {
dp[i][j] = max(dp[i - 1][j],
dp[i - 1][j - a[i - 1]] + a[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][m];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int backPack(int m, vector<int> &a) {
int n = a.size();
// state
vector<int> dp(m + 1);
// initial
// dp[0 to m] = 0;
// function
for (int i = 0; i < n; ++i) {
for (int j = m; j >= a[i]; --j) {
dp[j] = max(dp[j], dp[j - a[i]] + a[i]);
}
}
// answer
return dp[m];
}
};
不带价值的01背包,求方案数
563. 背包问题 V
解法1:背包型DP
class Solution {
public:
int backPackV(vector<int> &nums, int target) {
int n = nums.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(target + 1));
// initial
dp[0][0] = 1;
// dp[0][1 to target] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= target; ++j) {
if (j >= nums[i - 1]) {
dp[i][j] = dp[i - 1][j] +
dp[i - 1][j - nums[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][target];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int backPackV(vector<int> &nums, int target) {
int n = nums.size();
// state
vector<int> dp(target + 1);
// initial
dp[0] = 1;
// dp[1 to target] = 0;
// function
for (int i = 0; i < n; ++i) {
for (int j = target; j >= nums[i]; --j) {
dp[j] += dp[j - nums[i]];
}
}
// answer
return dp[target];
}
};
带价值的01背包,求最优解
125. 背包问题 II
解法1:背包型DP
class Solution {
public:
int backPackII(int m, vector<int> &a, vector<int> &v) {
int n = a.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
// initial
// dp[0][0 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j >= a[i - 1]) {
dp[i][j] = max(dp[i - 1][j],
dp[i - 1][j - a[i - 1]] + v[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][m];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int backPackII(int m, vector<int> &a, vector<int> &v) {
int n = a.size();
// state
vector<int> dp(m + 1);
// initial
// dp[0 to m] = 0;
// function
for (int i = 0; i < n; ++i) {
for (int j = m; j >= a[i]; --j) {
dp[j] = max(dp[j], dp[j - a[i]] + v[i]);
}
}
// answer
return dp[m];
}
};
分割等和子集
416. 分割等和子集
解法1:背包型DP
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % 2) {
return false;
}
int m = sum / 2;
// state
vector<vector<bool>> dp(n + 1, vector<bool>(m + 1));
// initial
dp[0][0] = true;
// dp[0][1 to m] = false;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j >= nums[i - 1]) {
dp[i][j] = dp[i - 1][j] ||
dp[i - 1][j - nums[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][m];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % 2) {
return false;
}
int m = sum / 2;
// state
vector<bool> dp(m + 1);
// initial
dp[0] = true;
// dp[1 to m] = false;
// function
for (int i = 1; i <= n; ++i) {
for (int j = m; j >= nums[i - 1]; --j) {
dp[j] = dp[j] || dp[j - nums[i - 1]];
}
}
// answer
return dp[m];
}
};
最后一块石头的重量 II
1049. 最后一块石头的重量 II
解法1:背包型DP
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int n = stones.size();
int sum = accumulate(stones.begin(), stones.end(), 0);
int m = sum / 2;
// state
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
// initial
// dp[0][0 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j >= stones[i - 1]) {
dp[i][j] = max(dp[i - 1][j],
dp[i - 1][j - stones[i - 1]] + stones[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return sum - 2 * dp[n][m];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int n = stones.size();
int sum = accumulate(stones.begin(), stones.end(), 0);
int m = sum / 2;
// state
vector<int> dp(m + 1);
// initial
// dp[0][0 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = m; j >= stones[i - 1]; --j) {
dp[j] = max(dp[j],
dp[j - stones[i - 1]] + stones[i - 1]);
}
}
// answer
return sum - 2 * dp[m];
}
};
目标和
494. 目标和
解法1:DFS
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int count = 0;
dfs(nums, target, 0, count);
return count;
}
void dfs(
vector<int>& vec, int sum,
int start, int& count
) {
if (start == vec.size()) {
if (sum == 0) {
++count;
}
return;
}
dfs(vec, sum - vec[start], start + 1, count);
dfs(vec, sum + vec[start], start + 1, count);
}
};
解法2:背包型DP
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int n = nums.size();
int sum = accumulate(nums.begin(), nums.end(), 0);
if (abs(target) > sum) {
return 0;
}
if ((target + sum) % 2) {
return 0;
}
int m = (target + sum) / 2;
// state
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
// initial
dp[0][0] = 1;
// dp[0][1 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j >= nums[i - 1]) {
dp[i][j] = dp[i - 1][j] +
dp[i - 1][j - nums[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][m];
}
};
解法3:背包型DP+滚动数组
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int n = nums.size();
int sum = accumulate(nums.begin(), nums.end(), 0);
if (abs(target) > sum) {
return 0;
}
if ((target + sum) % 2) {
return 0;
}
int m = (target + sum) / 2;
// state
vector<int> dp(m + 1);
// initial
dp[0] = 1;
// dp[1 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = m; j >= nums[i - 1]; --j) {
dp[j] += dp[j - nums[i - 1]];
}
}
// answer
return dp[m];
}
};
一和零
474. 一和零
解法1:背包型DP+滚动数组
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
// state
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
// initial
// dp[0 to m][0] = 0, dp[0][0 to n] = 0;
for (const auto& s: strs) {
int n0 = 0, n1 = 0;
for (const char& c: s) {
if (c == '0') {
++n0;
}
if (c == '1') {
++n1;
}
}
// function
for (int i = m; i >= n0; --i) {
for (int j = n; j >= n1; --j) {
dp[i][j] = max(dp[i][j],
dp[i - n0][j - n1] + 1);
}
}
}
// answer
return dp[m][n];
}
};
完全背包
不带价值的完全背包,求方案数
562. 背包问题 IV
解法1:背包型DP
class Solution {
public:
int backPackIV(vector<int> &nums, int target) {
int n = nums.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(target + 1));
// initial
dp[0][0] = 1;
// dp[0][1 to target] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= target; ++j) {
if (j >= nums[i - 1]) {
dp[i][j] = dp[i - 1][j] +
dp[i][j - nums[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][target];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int backPackIV(vector<int> &nums, int target) {
int n = nums.size();
// state
vector<int> dp(target + 1);
// initial
dp[0] = 1;
// dp[1 to target] = 0;
// function
for (int i = 0; i < n; ++i) {
for (int j = nums[i]; j <= target; ++j) {
dp[j] += dp[j - nums[i]];
}
}
// answer
return dp[target];
}
};
带价值的完全背包,求最优解
440. 背包问题 III
解法1:背包型DP
class Solution {
public:
int backPackIII(vector<int> &a, vector<int> &v, int m) {
int n = a.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
// initial
// dp[0][0 to m] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j >= a[i - 1]) {
dp[i][j] = max(dp[i - 1][j],
dp[i][j - a[i - 1]] + v[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][m];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int backPackIII(vector<int> &a, vector<int> &v, int m) {
int n = a.size();
// state
vector<int> dp(m + 1);
// initial
// dp[0][0 to m] = 0;
// function
for (int i = 0; i < n; ++i) {
for (int j = a[i]; j <= m; ++j) {
dp[j] = max(dp[j], dp[j - a[i]] + v[i]);
}
}
// answer
return dp[m];
}
};
零钱兑换 II
518. 零钱兑换 II
解法1:背包型DP
class Solution {
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(amount + 1));
// initial
dp[0][0] = 1;
// dp[0][1 to amount] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= amount; ++j) {
if (j >= coins[i - 1]) {
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][amount];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
// state
vector<int> dp(amount + 1);
// initial
dp[0] = 1;
// dp[1 to amount] = 0;
// function
for (int i = 0; i < n; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
dp[j] += dp[j - coins[i]];
}
}
// answer
return dp[amount];
}
};
377. 组合总和 IV
377. 组合总和 IV
解法1:背包型DP
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int n = nums.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(target + 1));
// initial
for (int i = 0; i <= n; ++i) {
dp[i][0] = 1;
}
// function
for (int j = 1; j <= target; ++j) {
for (int i = 1; i <= n; ++i) {
for (int k = i; k > 0; --k) {
if (j >= nums[k - 1] &&
dp[i][j] < INT_MAX - dp[i][j - nums[k - 1]]) {
dp[i][j] += dp[i][j - nums[k - 1]];
}
}
}
}
// answer
return dp[n][target];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int n = nums.size();
// state
vector<int> dp(target + 1);
// initial
dp[0] = 1;
// dp[1 to target] = 0;
// function
for (int j = 0; j <= target; ++j) {
for (int i = 0; i < n; ++i) {
if (j >= nums[i] &&
dp[j] < INT_MAX - dp[j - nums[i]]) {
dp[j] += dp[j - nums[i]];
}
}
}
// answer
return dp[target];
}
};
爬楼梯
70. 爬楼梯
解法1:坐标型DP
class Solution {
public:
int climbStairs(int n) {
// state
vector<int> dp(n + 1);
// initial
dp[0] = dp[1] = 1;
// function
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i - 2] + dp[i - 1];
}
// answer
return dp[n];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int climbStairs(int n) {
// state
vector<int> dp(n + 1);
// initial
dp[0] = 1;
// function
for (int j = 1; j <= n; ++j) {
for (int i = 1; i <= 2; ++i) {
if (j >= i) {
dp[j] += dp[j - i];
}
}
}
// answer
return dp[n];
}
};
零钱兑换
322. 零钱兑换
解法1:背包型DP
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
// state
vector<vector<int>> dp(n + 1, vector<int>(amount + 1));
// initial
fill(dp[0].begin(), dp[0].end(), INT_MAX);
dp[0][0] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= amount; ++j) {
if (j >= coins[i - 1] &&
dp[i][j - coins[i - 1]] < INT_MAX) {
if (dp[i - 1][j] < INT_MAX) {
dp[i][j] = min(dp[i - 1][j],
dp[i][j - coins[i - 1]] + 1);
} else {
dp[i][j] = dp[i][j - coins[i - 1]] + 1;
}
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][amount] == INT_MAX ? -1 : dp[n][amount];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
// state
vector<int> dp(amount + 1, INT_MAX);
// initial
dp[0] = 0;
// dp[1 to amount] = INT_MAX;
// function
for (int i = 0; i < n; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
if (dp[j - coins[i]] < INT_MAX) {
dp[j] = min(dp[j], dp[j - coins[i]] + 1);
}
}
}
// answer
return dp[amount] == INT_MAX ? -1 : dp[amount];
}
};
完全平方数
279. 完全平方数
解法1:背包型DP
class Solution {
public:
int numSquares(int n) {
// state
vector<vector<int>> dp(n + 1, vector<int>(n + 1));
// initial
fill(dp[0].begin(), dp[0].end(), INT_MAX);
dp[0][0] = 0;
// function
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= n; ++j) {
if (j >= i * i) {
dp[i][j] = min(dp[i - 1][j],
dp[i][j - i * i] + 1);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
// answer
return dp[n][n];
}
};
解法2:背包型DP+滚动数组
class Solution {
public:
int numSquares(int n) {
// state
vector<int> dp(n + 1, INT_MAX);
// initial
dp[0] = 0;
// dp[1 to n] = INT_MAX;
// function
for (int i = 1; i <= n; ++i) {
for (int j = i * i; j <= n; ++j) {
dp[j] = min(dp[j], dp[j - i * i] + 1);
}
}
// answer
return dp[n];
}
};