LeetCode 309 最佳买股票时机含冷冻期

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]的值。

思路顺下来不难,但想的过程还是觉得有点难度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值