Best Time to Buy and Sell Stock with Cooldown
Posted 太空工程车
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Best Time to Buy and Sell Stock with Cooldown相关的知识,希望对你有一定的参考价值。
题目:
给定一个数组nums,nums[i]代表的是在第i天的股价
例如:[1,2,3,0,10,4],数组代表的含义是:有6天的股价给你了,从第一天到第六天的股价分别是 1,2,3,0,10,4
你买卖股票的次数不限,但是有两个限制:
- 卖不能在买前面(不能买10,卖0)
- 一次交易完成之后,至少休息一天才能继续买入(买1,卖3之后,不能立刻买0,必须至少等一天)
问题:求出最大的获利数(对于例子来说,max=11,买1卖2,休息一天,买0卖10)
思路:
用dp来解。dp就一定要有状态和状态转换方程。
在每一天,都有3种状态:
- buy
- sell
- rest
那么我们就可以根据给定的数组,新建三个状态数组,代表每天对应的状态。
buy[n], sell[n], rest[n](n代表给定数组的长度)
那么状态就有了表示方法:
buy[i]:在第i天之前,以buy为结束的任何交易组合的最大利润
sell[i]:在第i天之前,以sell为结束的任何交易组合的最大利润
rest[i]:在第i天之前,以rest为结束的任何交易组合的最大利润
状态转换方程:(price是当前日期的股价)
buy[i] = max(rest[i-1] - price, buy[i-1]) sell[i] = max(buy[i-1] + price, sell[i-1]) rest[i] = max(sell[i-1], buy[i-1], rest[i-1])
以上的状态转换方程只是把题目的要求和之前的分析总结起来,例如:buy[i] = 今天买入(必须在休息之后才能买入) 或者 之前就有买入,保持不卖出。
还有一个隐藏的要素:
rest[i] = sell[i-1] 这个等式的意义在于,如果在今天休息,那么这天的收益就跟前一天sell相同
那么把这个等式代入,就有:
buy[i] = max(sell[i-2] - price, buy[i-1]) sell[i] = max(buy[i-1] + price, sell[i-1])
很好理解,如果要在这一天卖的话,至少要在前两天把之前的股票卖掉(因为间隔为1天)
在这之后,还可以更进一步优化,这里我们可以发现第i天的状态和第i-1天和第i-2天的状态有关,那么就可以不用状态数组,用两个变量来保存i-1和i-2的数据
代码:
1 public int maxProfit(int[] prices) { 2 int sell = 0, prevSell = 0, buy = Integer.MIN_VALUE, prevBuy; 3 for (int price : prices) { 4 prevBuy = buy; 5 buy = Math.max(prevSell - price, prevBuy); //这里buy和sell的赋值顺序不能变,因为prevSell在这里相当于方程中的sell[i-2] 6 prevSell = sell; //到这里,prevSell就真正变成了sell[i-1],变成了真正的previous sell 7 sell = Math.max(prevBuy + price, prevSell); 8 } 10 return sell; 11 }
以上是关于Best Time to Buy and Sell Stock with Cooldown的主要内容,如果未能解决你的问题,请参考以下文章
最强解析面试题:best-time-to-buy-and-sell-stock
最强解析面试题:best-time-to-buy-and-sell-stock
121. Best Time to Buy and Sell Stock
122. Best Time to Buy and Sell Stock II