之前收藏了极客时间的算法训练营3期 共21课,计划每一课写博客来记录学习,主要形式为
方法类型1
题1
题解
题2
题解
方法类型2
题1
题解
……
题目大体来自leetcode 和 acwing
主要记录和理解代码,所以基本完全搬运了视频题解代码,
个人学习感受体现在大致思路的总结和注释上。
第一题
每一天都有持股和不持股的两种状态。
初始化时每一种状态初始值都是极小。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
prices.insert(prices.begin(), 0);
vector<vector<int>> f(n + 1, vector<int>(2, -1e9));
f[0][0] = 0;
for (int i = 1; i <= n; i++) {
f[i][1] = max(f[i][1], f[i - 1][0] - prices[i]);
f[i][0] = max(f[i][0], f[i - 1][1] + prices[i]);
for (int j = 0; j < 2; j++) {
f[i][j] = max(f[i][j], f[i - 1][j]);
}
}
return f[n][0];
}
};
第二题
多一些状态而已
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
prices.insert(prices.begin(), 0);
vector<vector<vector<int>>> f(n + 1,vector<vector<int>>(2, vector<int>(k + 1, -1e9)));
f[0][0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j < 2; j++)
for (int m = 0; m <= k; m++) {
//没有用完次数可以尝试买入
if (m > 0) f[i][1][m] = max(f[i][1][m], f[i - 1][0][m - 1] - prices[i]);
//卖
f[i][0][m] = max(f[i - 1][1][m] + prices[i], f[i][0][m]);
//歇
f[i][j][m] = max(f[i][j][m], f[i - 1][j][m]);
}
int ans = -1e9;
for (int i = 0; i <= k; i++) {
//买几次都有可能
ans = max(ans, f[n][0][i]);
}
return ans;
}
};
第三题
只需要每次购买时减去费用即可。
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n = prices.size();
prices.insert(prices.begin(), 0);
vector<vector<int>> f(n + 1, vector<int>(2, -1e9));
f[0][0] = 0;
for (int i = 1; i <= n; i++) {
f[i][1] = max(f[i][1], f[i - 1][0] - prices[i] - fee);
f[i][0] = max(f[i][0], f[i - 1][1] + prices[i]);
for (int j = 0; j < 2; j++)
f[i][j] = max(f[i][j], f[i - 1][j]);
}
return f[n][0];
}
};
第四题
今天的状态规划明天的状态,向后规划。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<vector<int>>>
f(n + 1, vector<vector<int>>(2, vector<int>(2, -1e9)));
prices.insert(prices.begin(), 0);
f[0][0][0] = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++){
if (j == 0 && k == 0)
f[i + 1][1][k] = max(f[i + 1][1][k], f[i][j][k] - prices[i + 1]);
if (j == 1)
f[i + 1][0][1] = max(f[i + 1][0][1], f[i][j][k] + prices[i + 1]);
f[i + 1][j][max(0, k - 1)] = max(f[i + 1][j][max(0, k - 1)], f[i][j][k]);
}
}
}
return max(f[n][0][0], f[n][0][1]);
}
};
第五题
之前偷没偷过
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> f(n + 1, vector<int>(2, -1e9));
f[0][0] = 0;
nums.insert(nums.begin(), 0);
for (int i = 0; i < n; i++) {
for (int j = 0; j < 2; j++) {
f[i + 1][1] = max(f[i + 1][1], f[i][0] + nums[i + 1]);
f[i + 1][0] = max(f[i][0], f[i][1]);
}
}
return max(f[n][1], f[n][0]);
}
};
第六题
头尾相接,进行两次递归,第一次尝试偷第一家,第二次尝试最后一家
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if (n == 1) return nums[0];//即是头又是尾,特判。
nums.insert(nums.begin(), 0);
vector<vector<int>> f(2, vector<int>(2, -1e9));
//第一次, 可以选择偷第一家
f[0][0] = 0;
for (int i = 0; i < n; i++){
f[i + 1 & 1][0] = max(f[i & 1][0], f[i & 1][1]);
f[i + 1 & 1][1] = f[i & 1][0] + nums[i + 1];
for (int j = 0; j < 2; j++){
f[i & 1][j] = -1e9;
}
}
int ans = f[n & 1][0];
f[0][0] = -1e9;
f[0][1] = 0;
for (int i = 0; i < n; i++){
f[i + 1 & 1][0] = max(f[i & 1][0], f[i & 1][1]);
f[i + 1 & 1][1] = f[i & 1][0] + nums[i + 1];
for (int j = 0; j < 2; j++){
f[i & 1][j] = -1e9;
}
}
ans = max(ans, max(f[n & 1][0], f[n & 1][1]));
return ans;
}
};
第七题
注意初始化的值,为直接构建相应单词所需要的字母数量。
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.length();
int n = word2.length();
word1 = " " + word1;
word2 = " " + word2;
vector<vector<int>> f(m + 1, vector<int>(n + 1, 1e9));
for (int i = 0; i <= m; i++) f[i][0] = i;
for (int i = 0; i <= n; i++) f[0][i] = i;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) {
f[i][j] = min(f[i - 1][j - 1] + (word1[i] != word2[j]), min(f[i - 1][j] + 1, f[i][j - 1] + 1));
}
return f[m][n];
}
};
第八题
即找等于总和一半的子集,
|=可以对int使用,但是bool不行
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
for (int num : nums) sum += num;
if (sum % 2 == 1) return false;
vector<int> f(sum / 2 + 1, false);
f[0] = true;
for (int i = 0; i < nums.size(); i++)
for (int j = sum / 2; j >= nums[i]; j--) {
f[j] |= f[j - nums[i]];
}
return f[sum / 2];
}
};
第九题
完全背包问题,相应位置加上之前位置的方案总和。
class Solution {
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
coins.insert(coins.begin(), 0);
vector<int> f(amount + 1 , 0);
f[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = coins[i]; j <= amount; j++){
f[j] += f[j - coins[i]];
}
}
return f[amount];
}
};