视频讲解:https://www.bilibili.com/video/BV1WG411K7AR
1.本题的关键点在于(此处借用卡哥的话)。关键在于至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖。我一直以为这个到底买几次是需要我限定去判定到底是哪个方法是最大利润的,其实就算是只买卖一次就可以求出结果的话,第二次也可以当天买入然后卖出这样将最大利润存在dp[prices.size() - 1][4]里面。本题还是需要厘清dp数组的含义,更重要的是每一个状态到底应该由哪一个状态推导出来的。
就像是本题我相信一定会有同学有这样的想法包括我也一样:
这里借助代码随想录
确定dp数组以及下标的含义
一天一共就有五个状态,
0:没有操作 (其实我们也可以不设置这个状态)
1:第一次持有股票
2:第一次不持有股票
3:第二次持有股票
4:第二次不持有股票
为什么第一次持有的股票的状态不是像 买卖股票的最佳时机II里一样是由第一次不持有股票的状态 减去当天的股票价值 :这个就是对于本题的每个dp数组的状态转移的应该由哪个部分推导过来的不清楚,本题要求不能同时持有两张股票,所以第一次持有应该由不操作的位置转移过来然后减去当天对应的股票价钱,而上一题里是由第一天不持有的状态推导过来的原因,是因为要将利润也从状态转移中提取出来,而不是再从0开始,总的来说第一次和第二次不是向前两个题一样自己和自己玩,就是说不是dp[i][1]和dp[i][2]进行状态转移,而是从无操作的状态转移到第一次操作,然后第一次的操作转移到第二次操作,比较直观的就是这两行代码:
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
就是从第一天不持有向第二天持有状态转移的操作,同理这就是为什么第一天持有为什么从无操作开始进行状态转移的。
CPP
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(prices.size(), 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 < prices.size(); i++){
dp[i][0] = dp[i - 1][0];
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return dp[prices.size() - 1][4];
}
};