1、对题目进行分析,不难发现每一天用户可以选择的操作包括以下几种情况,且有如下限制:
1)买入:(第一次购买股票)||(已经度过冷冻期)因为无法买卖多支股票,所以度过冷冻期后就可以默认当前没有需要卖出的股票,需要再次进行购买
2)卖出:(有买入的股票)
3)冷冻期:(前一天卖出了股票)
4)既不买入也不卖出
设想可否通过回溯的算法实现对所有可能情况的全遍历。
递归函数的参数包括:当前的收益,手中股票购入价格,当前状态(注:对于当前的状态,可以划分为0:可以购买;1:有未卖出股票;2:冷冻期)。
递归内容包括:根据上一个操作,使用当前可行的全部操作进行递归,在这一过程中计算并更新最大收益。对困难程度上暴力搜索,结果果然是超出时间限制,看大神解题吧。
func maxProfit(prices []int) int {
var maxPro int = 0
var helper func(pro, price, state, day int)
helper=func(pro, price, state, day int) {
if day>=len(prices) {state=3}
switch state{
case 0:
helper(pro,prices[day],1,day+1) // 买进
helper(pro,-1,0,day+1) // 不买进
case 1:
helper(pro+prices[day]-price,-1,2,day+1)// 卖出
helper(pro,price,1,day+1) // 不卖出
case 2:
helper(pro,-1,0,day+1) // 冷冻期不进行操作
default:
maxPro=getMax(maxPro, pro)
}
}
helper(0, -1, 0, 0)
return maxPro
}
func getMax(a, b int) int {
if a>=b {
return a
}else{ return b }
}
2、真的是看着大佬把过程一路优化,真厉害啊。
递归的优化越来越感觉就是在用空间换时间,用多出来的空间记录中间各个计算过的状态,避免重复的计算,根据这一思路,将上面的三个状态通过三个数组进行存储。
sell []int :sell[i] 表示到第i天的最后一个操作是卖出的最大利润。
cold []int:cold[i] 表示到第i天的最后一个操作是冷冻期的最大利润。
buy []int:buy[i] 表示到第i天的最后一个操作是买入的最大利润。
那么对于这三个数组,存在如下的计算关系。
sell[i]=max(sell[i-1], buy[i-1]+prices[i])
buy[i]=max(buy[i-1], cold[i-1]-prices[i])
cold[i]=max(cold[i-1], sell[i-1], buy[i-1]) ps. 这里有些没想到,后来反应过来冷冻期可以发生在任何操作之后,所以选择前一天各个操作的最大值即可。
但是顺着任何操作后都可以有冷冻期的思路想,就会发现可能会出现 [buy, cold, buy] 的情况,因为购买操作后允许连接冷冻期,而冷冻期后则可以进行购买。针对这一问题,观察上述三个计算,不难发现,buy和cold之间存在如下数量关系,buy[i]<=cold[i],也就是说 cold[i]的表达式可以进一步简化为 cold[i]=max(cold[i-1], sell[i-1]),从这个表达式不难看出,按照上述计算,虽然允许冷冻期的最后一个操作是buy,但是这种情况并不会发生,也就不会存在上述的问题。
进一步优化:根据简化后的cold不难看出,可以省略cold数组,更新sell和buy数组如下:
buy[i]=max(buy[i-1], sell[i-2]-prices[i])
sell[i]=max(sell[i-1], buy[i-1]+prices[i])
观察发现,sell和buy的更新都是依赖i-1或者i-2的结果,所以可以不使用数组的数据结构,直接用O(1)大小的空间存储,最后实现的代码如下(参考了[LeetCode] Best Time to Buy and Sell Stock with Cooldown 买股票的最佳时间含冷冻期 - Grandyang - 博客园 (cnblogs.com)):
func maxProfit(prices []int) int {
var sell, buy, preBuy, preSell int=0, -1<<31, 0, 0
for _, v := range prices {
preBuy=buy
buy=getMax(preBuy, preSell-v)
preSell=sell
sell=getMax(preSell, preBuy+v)
}
return sell
}
func getMax(a, b int) int {
if a>=b {
return a
}else{ return b }
}
单纯看代码可能会有疑问,buy应该等于sell[i-2]+prices[i],为什么没有preprebuy的值,而是直接用prebuy,通过观察不难发现,在循环中,是先更新计算prebuy和buy,在更新buy的时候,presell还没有进行跟新,其中存储的其实就是sell[i-2]的值。
思路顺下来不难,但想的过程还是觉得有点难度。