分析,这里不同于其他几道题,有交易次数的限制。对于任意一天 i,我们有五种可选择的状态,(因为题目限制了买入之前必须卖出)
- 不操作
- 只买入一次
- 买一次,卖一次
- 买一次,卖一次,再买一次
- 买一次,卖一次,再买一次,再卖一次。
因此有:
1.定义dp数组:
下标从0开始
dp[i][0] 表示第i天交易完之后 ,不操作的最大利润。
dp[i][1] 表示第i天交易完之后 ,只买入一次的最大利润。
dp[i][2] 表示第i天交易完之后 ,买一次,卖一次的最大利润。
dp[i][3] 表示第i天交易完之后 ,买一次,卖一次,再买一次的最大利润。
dp[i][4] 表示第i天交易完之后 ,买一次,卖一次,再买一次,再卖一次的最大利润。
则我们要的结果为:
第n-1天交易完后,手里没有股票的最大利润。
2.状态转移方程:
一:dp[i][0] = dp[i-1][0]
解释:
第i天交易完后,不进行任何操作,只能为第i-1天同样不进行任何操作。
二:dp[i][1] = max(dp[i-1][1],dp[i-1][0]-price[i])
解释:
第i天交易完后,买入了一次。可能的情况有:
1.第i-1天手里就有股票。所以为:dp[i-1][1]
2.第i-1天手里没有股票,但是第i天买入股票了,所以为 dp[i-1][0]-price[i] 。
三:dp[i][2] = max(dp[i-2][1],dp[i-1][0]+price[i])
解释:
第i天交易完后,买一次,卖一次。可能的情况有:
1.第i-1天手里就买完且卖出了。所以为:dp[i-1][2]
2.第i-1天手里买入了,但是第i天卖出股票了,所以为 dp[i-1][1]+price[i] 。
四:dp[i][3] = max(dp[i-1][3],dp[i-1][2]-price[i])
解释:
第i天交易完后,买一次,卖一次,再买一次。可能的情况有:
1.第i-1天买完且卖出,后来又买入了。所以为:dp[i-1][3]
2.第i-1天买一次,卖一次后,第i天买入股票了,所以为 dp[i-1][2]-price[i] 。
五:dp[i][4] = max(dp[i-1][4],dp[i-1][3]+price[i])
解释:
第i天交易完后,买一次,卖一次,再买一次,再卖一次。可能的情况有:
1.保持第i-1天的状态:dp[i-1][4]
2.前面交易完成一次且买入股票后,第i天卖出股票了,所以为 dp[i-1][3]+price[i] 。
3.初始化:
dp[0][0]表示第0天不操作,为0。
dp[0][1]表示第0天买入,为-price[0]。
dp[0][2]表示第0天买入后卖出,为0。
dp[0][3]表示第0天买入卖出再买入,为-price[0]。
dp[0][4]表示第0天两次交易,为0。
代码如下
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
vector<vector<int>> dp(n,vector<int>(5,0));
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;
for(int i=1;i<n;i++)
{
dp[i][0] = dp[i-1][0];
dp[i][1] = max(dp[i-1][0]-prices[i],dp[i-1][1]);
dp[i][2] = max(dp[i-1][1]+prices[i],dp[i-1][2]);
dp[i][3] = max(dp[i-1][2]-prices[i],dp[i-1][3]);
dp[i][4] = max(dp[i-1][3]+prices[i],dp[i-1][4]);
}
return dp[n-1][4];
}
};