309.买卖股票的最佳时机含冷冻期
给定一个整数数组 prices,其中第 prices[i] 表示第 i 天的股票价格。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一只股票):卖出股票后,你无法在第二天买入股票(即冷冻期为一天)。注意:你不能同时参与多笔交易(必须在再次购买前出售掉之前的股票)。
与之前的买卖股票问题不同,本题要求在卖完股票后,存在一天的冷冻期,不得立马购入股票。下面从动态规划五部曲仔细分析该题:
1. 定义 dp 数组的含义,我们定义 dp[i][j] 为第 i 天的第 j 种状态的最大利润;
2. 确定递推公式,我们将每天的状态划分如下:持有(买入)股票;不持有股票;卖出股票;冷冻期。(状态 0 ~ 3)
对应的递推公式分别为:
dp[i][0] = max(dp[i - 1][0], max(dp[i-1][1] - prices[i], dp[i-1][3] - prices[i]));
dp[i][1] = max(dp[i-1][1], max(dp[i-1][2], dp[i-1][3]));
dp[i][2] = dp[i - 1][0] + prices[i];
dp[i][3] = dp[i-1][2]。
状态 0 能由状态 0、1、3 推导,无法由状态 3 推导得到,因为卖出股票后无法立即买入;状态 1 能由状态 1、2、3 推导,不持有股票的前一天可能为不持有股票、卖出股票和冷冻期状态;状态 2 仅能由状态 0 推导,卖出的前一天必定是持有(买入)股票状态;状态 4 必由状态 2 推导,冷冻期前一天必为卖出。
3. 初始化,dp[0][0] = -prices[i],dp[0][1~3] = 0;
4. 遍历顺序,从前向后;
5. 出错时,打印 dp 数组 debug。
class Solution {
public:
int maxProfit(vector<int> &prices) {
int len = prices.size();
if (len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(4, 0));
dp[0][0] = -prices[0];
dp[0][1] = 0; dp[0][2] = 0; dp[0][3] = 0;
for (int i = 1; i < len; ++i) {
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1] - prices[i], dp[i - 1][3] - prices[i]));
dp[i][1] = max(dp[i - 1][1], max(dp[i - 1][2], dp[i - 1][3]));
dp[i][2] = dp[i - 1][0] + prices[i];
dp[i][3] = dp[i - 1][2];
}
return max(dp[len - 1][1], max(dp[len - 1][2], dp[len - 1][3]));
}
};
714.买卖股票的最佳时机含手续费
只要减去手续费即可,因为有手续费的存在,所以不交易可能比交易的获利更大,所以取 dp[len - 1][0] 和 dp[len - 1][1] 的最大值。
class Solution {
public:
int maxProfit(vector<int> &prices, int fee) {
int len = prices.size();
if (len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(2, 0));
dp[0][0] = 0 - prices[0]; dp[0][1] = dp[0][0] + prices[0];
for (int i = 1; i < len; ++i) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
}
return max(dp[len - 1][0], dp[len - 1][1]);
}
};