Leetcode309. Best Time to Buy and Sell Stock with Cooldown

Leetcode309. Best Time to Buy and Sell Stock with Cooldown

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:
Input: [1,2,3,0,2]
Output: 3 
Explanation: transactions = [buy, sell, cooldown, buy, sell]
动态规划
第一步:定义状态

在这里插入图片描述

S0是没有股票(空仓),S1是持有股票(持仓),S2是冷冻期。s[i]表示到第i天为止所赚的最大利润(即在第 i 天的操作结束后我目前一共赚到的利润)。

第二步 思考状态转移方程
  • 如果第 i 天的状态是空仓(s0),它可以由第 i-1 天的两个状态转换而来:

    ① 第 i-1 天的状态是空仓,我到 i-1 天为止赚的利润为 s0[i-1] ,在第 i 天也不买入,截至第 i 天的最大利润为 s0[i] = s0[i-1]

    ② 第 i-1 天的状态是冷冻期,我到 i-1 天为止赚的利润为 s2[i-1] ,截至第 i 天的最大利润为 s0[i] = s2[i-1]

    ③ 由①②我们可以得出空仓状态的状态转移方程:

    s0[i] = max(s0[i - 1], s2[i - 1]);
    
  • 如果第 i 天的状态是持仓

    ① 第 i-1 天的状态是空仓,我到 i-1 天为止赚的利润为 s0[i-1],然后在第 i 天买入股票花费了 price[i] ,这样截至第 i 天的最大利润为 s1[i] = s0[i-1] - price[i]

    ② 第 i-1 天的状态是持仓,我到 i-1 天为止赚的利润为 s1[i-1] ,在第 i 天不卖出,截至第 i 天的最大利润为 s0[i] = s1[i-1]

    ③ 由①②我们可以得出持仓状态的状态转移方程:

    s1[i] = max(s0[i-1] - price[i], s1[i-1])
    
  • 如果第 i 天的状态是冷冻期:那我第 i-1 天一定卖出了股票,所以截至第 i 天的最大利润一定是

    s2[i] = s1[i - 1] + price[i]
    
第三步 思考初始化

结合实际情况,不能理所当然把三个全部初始化为0

第一天商品的价格为 price[0],截至第一天,我们获得的最大利润 s[0] 可以是:
① 空仓:第一天什么都不做,s0[0] = 0
② 持仓:第一天买入股票,s1[0] = -price[0]
③ 冷冻期:不可能进入冷冻期,s2[0] = Integer.MIN_VALUE

第四步 思考输出

最后一天我们不可能再买入,即不可能是持仓状态,只可能卖出或者是冷冻期。所以第 i 天的最大利润是

result = max(s0[i],s2[i])
public int maxProfit(int[] prices) {
    int len = prices.length;
    if (len <= 1) {
        return 0;
    }
   
    int[] s0 = new int[len]; 
    int[] s1 = new int[len]; 
    int[] s2 = new int[len]; 

    s0[0] = 0;
    s1[0] = -prices[0];
    s2[0] = Integer.MIN_VALUE;

    for (int i = 1; i < len; i++) {
        s0[i] = Math.max(s0[i - 1], s2[i - 1]);
        s1[i] = Math.max(s1[i - 1], s0[i - 1] - prices[i]);
        s2[i] = Math.max(s2[i - 1], s1[i - 1] + prices[i]);
    }
    return Math.max(s0[len - 1], s2[len - 1]);
}
第五步 思考状态压缩

因为我们只用到了上一次的状态,因此压缩状态

public int maxProfit(int[] prices) {
    if (prices == null || prices.length < 2)  return 0;
    int[] s0 = new int[2];
    int[] s1 = new int[2];
    int[] s2 = new int[2];
    s0[0] = 0;
    s1[0] = -prices[0];
    s2[0] = Integer.MIN_VALUE;

    for (int i = 1; i < prices.length; ++i) {
      s0[i%2] = Math.max(s0[(i-1)%2], s2[(i-1)%2]);
      s1[i%2] = Math.max(s1[(i-1)%2], s0[(i-1)%2] - prices[i]);
      s2[i%2] = s1[(i-1)%2] + prices[i];
    }

    return Math.max(s0[(prices.length-1)%2], s2[(prices.length-1)%2]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值