今天又做到了一道买卖股票 309. Best Time to Buy and Sell Stock with Cooldown 的题,我思考了一会没做出来,参考了别人的解答才理解的。
这道题相比之前一道类似的题 122. Best Time to Buy and Sell Stock II 的区别就是加上了一个cooldown的限制条件,就是卖完股票的接下来一天不能再接着买,至少需要等待一天之后才能买。中间不能参与交易的那些日期就称为所谓的“cooldown”时期,现在问最大的收益是多少?
这道题我们想一下,对于每一天,有几种可能的状况:
- 买入股票
- 卖出股票
- cooldown(啥都不做,没法交易)
我们想,影响我们某一天为止的累计收益其实只有买入和卖出操作,而且当我们买入股票时,由于花钱了,累计收益肯定是减少的,当我们卖出股票时,由于挣钱了,累计收益肯定是增加的。最后是要计算最大的累计收益,所以我们只需要在每次卖出股票的时候更新我们的最大收益。
由于这道题是要用dp做的,所以我们设置两个数组buy和sell,它们的作用如下:
- buy[i]表示第i天的状况是“买入股票”的最大累计收益
- sell[i]表示第i天的状况是“卖出股票”的最大累计收益
想一下buy[0]是多少?
buy[0]指的是第0天买入股票对应的最大收益,有人可能会说,第0天买入股票没有收益呀,不对,你买入了股票,说明你花钱了,你目前的收益是负的,以后无论你什么时候卖出去,都是在当前的负的基础上加。所以buy[0] = -prices[0],同理buy[1] = -prices[1]
然后再想一下sell[0]是多少?
第0天就卖?之前都没买怎么去卖,所以sell[0] = 0,sell[1]就不同了,如果prices[1] > prices[0]的话,sell[1]应该等于prices[1] - prices[0],否则还是等于0。
我们想一想,buy[i]的值跟之前哪些值有关?我们分2种情况讨论:
-
之前含有未完成的交易,如果之前一天执行的也是买入操作,那么如果换成今天买入,累计收益会不会增加呢?
那么这取决于什么呢?就是昨天跟今天买入的价格哪个更便宜,注意,由于买入时累计收是益减少的,所以其实比的是谁减少的更少,即花的钱比较少,这样收益就更大。
有人说你怎么不说前天也执行的是“买入”操作呢?因为我们在计算buy[i-1]的时候就考虑过buy[i-2],所以我们在计算buy[i]的时候只考虑buy[i-1],而不考虑buy[i-2],换句话说,这种情况下我们只需要和前一天做比较。 -
之前不含有未完成的交易,那么今天要买入,昨天就必须是cooldown,当然前天也可能是cooldown,但我们这里需要考虑的是,如果前天卖过股票,那么当前的最大收益是多少?这个就很简单,因为买入股票累计收益是减少的,所以今天的累计收益是sell[i-2]-prices[i]。
有人可能又要问了,既然你说前天也可能是cooldown,那么你怎么不考虑sell[i-3]-prices[i],还是那句话,计算sell[i-2]的时候考虑过sell[i-3]。
综上,我们得到第一个状态转移方程:
delta = price[i] - price[i - 1]
buys[i] = max(sells[i - 2] - prices[i], buys[i - 1] - delta)
同样,我们再想想,sell[i]的值跟之前哪些值有关?我们分2种情况讨论:
- 之前含有完成的交易,如果之前一天执行的也是卖出操作,那么如果换成今天卖出,累计收益会不会增加呢?
那么这取决于什么呢?就是昨天跟今天卖出的价格哪个更贵。所以我们这里需要考虑sells[i - 1] + delta的值 - 之前含有未完成的交易,这个简单,就是单纯的卖出去,累计收益只需要加上这一天卖出去的价格。
综上,我们得到第二个状态转移方程:
delta = price[i] - price[i - 1]
sells[i] = max(buys[i - 1] + prices[i], sells[i - 1] + delta)
如果你仔细观察,你会发现这和上面的逻辑是一样的。
于是我们写出如下代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if(len==0 || len==1) return 0;
vector<int> buy(len, 0);//buy[i]表示第i天选择买入股票所得最大收益
vector<int> sell(len, 0);//sell[i]表示第i天选择卖掉股票所得最大收益
buy[0] = -prices[0]; buy[1] = -prices[1];
sell[1] = max(0, prices[1]-prices[0]);
int max_profit = max(0, sell[1]);
for(int i = 2; i < len; i++){
int delta = prices[i] - prices[i-1];
sell[i] = max(sell[i-1]+delta, buy[i-1]+prices[i]);
buy[i] = max(buy[i-1]-delta, sell[i-2]-prices[i]);
max_profit = max(max_profit, sell[i]);
}
return max_profit;
}
};
点击submit
芜湖,起飞!
参考文章: https://blog.csdn.net/aishangyutian12/article/details/51881654