1. 题目链接:309. 买卖股票的最佳时机含冷冻期
2. 题目描述:
给定一个整数数组
prices
,其中第prices[i]
表示第*i*
天的股票价格 。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
**注意:**你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
示例 2:
输入: prices = [1] 输出: 0
提示:
1 <= prices.length <= 5000
0 <= prices[i] <= 1000
3. 解法(动态规划):
3.1 算法思路:
1. 状态表示:
以某一个位置为结尾,结合题目要求,定义一个状态表示:
由于有买入、可交易、冷冻期三个状态,因此我们可以选择用三个数组:
dp[i][0]
表示:第i
天结束后,处于买入状态,此时的最大利润
dp[i][1]
表示:第i
天结束后,处于可交易状态,此时的最大利润
dp[i][2]
表示:第i
天结束后,处于冷冻期状态,此时的最大利润
2. 状态转移方程:
交易规则:
处于买入状态的时候,我们现在有股票,此时不能买股票,只能继续持有股票,或者卖出股票
处于卖出状态的时候:如果在冷冻期,不能买入;如果不在冷冻期,才能买入
- 对于
dp[i][0]
,我们有两种情况能达到这个状态:
在i-1
天持有股票,此时最大收益应该和i-1
天的保持一致:dp[i-1][0]
在i
天买入股票,那我们应该选择i-1
天不在冷冻期的时候买入,由于买入需要花费钱,所以此时的最大收益为:dp[i-1][1]-prices[i]
两种情况应该取最大值,因此:dp[i][0]=max(dp[i-1][0],dp[i-1][1]-proces[i])
- 对于
dp[i][1]
,我们有两种情况能达到这个状态:
在 i-1
天的时候,已经处于冷冻期,然后什么也不干到第i
天,此时对应的状态为:dp[i-1][2]
在 i-1
天的时候,手上没有股票,也不在冷冻期,但是依旧什么也不干到第i
天,此时的对应的状态为 dp[i-1][1]
两种情况的最大值,因此:dp[i][1]=max(dp[i-1][1],dp[i-1][2]);
- 对于
dp[i][2]
,我们只有一种情况能达到这个状态:
在 i-1
天的时候,卖出股票
因此对应的状态转移方程为:dp[i][2]=dp[i-1][0]+prices[i];
3. 初始化:
三种状态都会用前一个位置的值,因此需要初始化每一行的每一个位置:
dp[0][0]
:此时要想处于买入状态,必须把第一天的股票买了,因此 dp[0][0]=-prices[0]
;
dp[0][1]
: 啥也不干即可,因此 dp[0][1]=0
;
dp[0][2]
: 手里没有股票,买一下卖一下就处于冷冻期,此时收益为0,因此 dp[0][2]=0
4. 填表顺序:
根据状态表示:我们要三个表一起填,每一个表从左往右
5. 返回值:
应该返回卖出状态下的最大值,因此应该返回 max(dp[n-1][1],dp[n-1][2]);
3.2 C++算法代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
vector<vector<int>>dp(n,vector<int>(3)); // 创建大小为n的二维数组dp,每个元素初始化为0
dp[0][0]=-prices[0]; // 第一天持有股票的利润为买入价格的相反数
for(int i=1;i<n;i++) // 遍历每一天的股票价格
{
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]); // 第i天持有股票的利润为前一天持有股票的利润和前一天不持有股票但是买入股票的利润的较大值
dp[i][1]=max(dp[i-1][1],dp[i-1][2]); // 第i天不持有股票的利润为前一天不持有股票的利润和前一天卖出股票的利润的较大值
dp[i][2]=dp[i-1][0]+prices[i]; // 第i天卖出股票的利润为前一天持有股票的利润加上当天的股票价格
}
return max(dp[n-1][1],dp[n-1][2]); // 返回最后一天不持有股票的利润和最后一天卖出股票的利润的较大值
}
};