【算法笔记】状态机DP之买卖股票问题通用解法
🔥个人主页:大白的编程日记
🔥专栏:算法笔记
文章目录
前言
哈喽,各位小伙伴大家好!今天我们讲的是买卖股票问题的通用解法。话不多说,我们进入正题!向大厂冲锋!
一.买卖股票的最佳时机
- 题目:买卖股票的最佳时机
- 思路分析
- 代码实现
注意这里ans初始化为0表示不交易 同时这里先包含卖入点的股票价格最小值不要紧 因为当天买入当天卖出利润为0 不影响结果!
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
int min_price = prices[0];
for (int p : prices) {
ans = max(ans, p - min_price);
min_price = min(min_price, p);
}
return ans;
}
};
二.买卖股票的最佳时机2
-
题目:买卖股票的最佳时机2
-
思路分析
- 代码实现
记忆化搜索:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<array<int, 2>> memo(n, {-1, -1}); // -1 表示还没有计算过
auto dfs = [&](this auto&& dfs, int i, bool hold) -> int {
if (i < 0) {
return hold ? INT_MIN : 0;
}
int& res = memo[i][hold]; // 注意这里是引用
if (res != -1) {
return res; // 之前计算过
}
if (hold) {
return res = max(dfs(i - 1, true), dfs(i - 1, false) - prices[i]);
}
return res = max(dfs(i - 1, false), dfs(i - 1, true) + prices[i]);
};
return dfs(n - 1, false);
}
};
动态规划:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<array<int, 2>> f(n + 1);
f[0][1] = INT_MIN;
for (int i = 0; i < n; i++) {
f[i + 1][0] = max(f[i][0], f[i][1] + prices[i]);
f[i + 1][1] = max(f[i][1], f[i][0] - prices[i]);
}
return f[n][0];
}
};
三.买卖股票的最佳时机4
-
题目:买卖股票的最佳时机4
-
思路分析
-
代码实现
记忆化搜索:
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
vector memo(n, vector<array<int, 2>>(k + 1, {-1, -1})); // -1 表示还没有计算过
auto dfs = [&](this auto&& dfs, int i, int j, bool hold) -> int {
if (j < 0) {
return INT_MIN / 2; // 除 2 防止溢出
}
if (i < 0) {
return hold ? INT_MIN / 2 : 0;
}
int& res = memo[i][j][hold]; // 注意这里是引用
if (res != -1) { // 之前计算过
return res;
}
if (hold) {
return res = max(dfs(i - 1, j, true), dfs(i - 1, j - 1, false) - prices[i]);
}
return res = max(dfs(i - 1, j, false), dfs(i - 1, j, true) + prices[i]);
};
return dfs(n - 1, k, false);
}
};
动态规划:
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
vector f(n + 1, vector<array<int, 2>>(k + 2, {INT_MIN / 2, INT_MIN / 2}));
for (int j = 1; j <= k + 1; j++) {
f[0][j][0] = 0;
}
for (int i = 0; i < n; i++) {
for (int j = 1; j <= k + 1; j++) {
f[i + 1][j][0] = max(f[i][j][0], f[i][j][1] + prices[i]);
f[i + 1][j][1] = max(f[i][j][1], f[i][j - 1][0] - prices[i]);
}
}
return f[n][k + 1][0];
}
};
恰好K次
- 递归边界判断条件增加j>0即可。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
vector memo(n, vector<array<int, 2>>(k + 1, {-1, -1})); // -1 表示还没有计算过
auto dfs = [&](this auto&& dfs, int i, int j, bool hold) -> int {
if (j < 0) {
return INT_MIN / 2; // 除 2 防止溢出
}
if (i < 0) {
return hold || j>0 ? INT_MIN / 2 : 0;
}
//增加j>0即可
int& res = memo[i][j][hold]; // 注意这里是引用
if (res != -1) { // 之前计算过
return res;
}
if (hold) {
return res = max(dfs(i - 1, j, true), dfs(i - 1, j - 1, false) - prices[i]);
}
return res = max(dfs(i - 1, j, false), dfs(i - 1, j, true) + prices[i]);
};
return dfs(n - 1, k, false);
}
};
至少K次
- 只需要判断天数为0时 交易次数k是否<=0即可
#include <vector>
#include <array>
#include <climits>
using namespace std;
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
if (n < 2) return 0; // 如果天数少于2天,无法进行交易
vector<vector<array<int, 2>>> memo(n, vector<array<int, 2>>(k + 1, {0, INT_MIN}));
auto dfs = [&](int i, int j, bool hold) -> int {
if (j <= 0) return 0; // 如果交易次数为0或负数,无法进行交易
if (i == -1) return INT_MIN; // 如果天数用完,还没有完成至少k次交易,返回INT_MIN
int& res = memo[i][j][hold];
if (res != 0 && res != INT_MIN) return res; // 之前计算过
if (!hold) {
res = max(dfs(i - 1, j, false), dfs(i - 1, j, true) + prices[i]);
} else {
res = max(dfs(i - 1, j, true), dfs(i - 1, j - 1, false) - prices[i]);
}
return res;
};
int maxProfit = INT_MIN;
for (int j = 1; j <= k; ++j) { // 至少1次交易
maxProfit = max(maxProfit, dfs(0, j, false));
}
return maxProfit;
}
};
四.买卖股票的最佳时机3
- 题目:买卖股票的最佳时机3
- 思路分析
这道题就是买卖股票的最佳时机4的k为2的情况 - 代码分析
记忆化搜索
class Solution {
public:
int maxProfit( vector<int>& prices) {
int n = prices.size();
int k=2;
vector memo(n, vector<array<int, 2>>(k + 1, {-1, -1})); // -1 表示还没有计算过
auto dfs = [&](this auto&& dfs, int i, int j, bool hold) -> int {
if (j < 0) {
return INT_MIN / 2; // 除 2 防止溢出
}
if (i < 0) {
return hold ? INT_MIN / 2 : 0;
}
int& res = memo[i][j][hold]; // 注意这里是引用
if (res != -1) { // 之前计算过
return res;
}
if (hold) {
return res = max(dfs(i - 1, j, true), dfs(i - 1, j - 1, false) - prices[i]);
}
return res = max(dfs(i - 1, j, false), dfs(i - 1, j, true) + prices[i]);
};
return dfs(n - 1, k, false);
}
};
动态规划
class Solution {
public:
int maxProfit( vector<int>& prices) {
int k=2;
int n = prices.size();
vector f(n + 1, vector<array<int, 2>>(k + 2, {INT_MIN / 2, INT_MIN / 2}));
for (int j = 1; j <= k + 1; j++) {
f[0][j][0] = 0;
}
for (int i = 0; i < n; i++) {
for (int j = 1; j <= k + 1; j++) {
f[i + 1][j][0] = max(f[i][j][0], f[i][j][1] + prices[i]);
f[i + 1][j][1] = max(f[i][j][1], f[i][j - 1][0] - prices[i]);
}
}
return f[n][k + 1][0];
}
};
五.买卖股票的最佳时机含冷冻期
-
思路分析
- 代码实现
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<array<int, 2>> memo(n, {-1, -1}); // -1 表示还没有计算过
auto dfs = [&](this auto&& dfs, int i, bool hold) -> int {
if (i < 0) {
return hold ? INT_MIN : 0;
}
int& res = memo[i][hold]; // 注意这里是引用
if (res != -1) { // 之前计算过
return res;
}
if (hold) {
return res = max(dfs(i - 1, true), dfs(i - 2, false) - prices[i]);
}
return res = max(dfs(i - 1, false), dfs(i - 1, true) + prices[i]);
};
return dfs(n - 1, false);
}
};
六.买卖股票的最佳时机含手续费
-
思路分析
在买卖股票2的当天买入情况利润-手续费即可。
-
代码实现
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n = prices.size();
vector<array<int, 2>> memo(n, {-1, -1}); // -1 表示还没有计算过
auto dfs = [&](this auto&& dfs, int i, bool hold) -> int {
if (i < 0) {
return hold ? INT_MIN / 2 : 0; // 防止溢出
}
int& res = memo[i][hold]; // 注意这里是引用
if (res != -1) {
return res; // 之前计算过
}
if (hold) {
return res = max(dfs(i - 1, true), dfs(i - 1, false) - prices[i]);
}
return res = max(dfs(i - 1, false), dfs(i - 1, true) + prices[i] - fee);
};
return dfs(n - 1, false);
}
};
后言
这就是买卖股票问题的通用解法。大家自己好好消化!今天就分享到这! 感谢各位的耐心垂阅!咱们下期见!拜拜~