【Leetcode】309. Best Time to Buy and Sell Stock with Cooldown

题目地址:

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/

给定每天的股价 p p p,必须卖出后才能买入,并且每次卖出的时候第二天是不能买的,必须至少隔一天。问能获得的最大利润。

法1:状态机,从cash角度考虑。定义三个状态,第一个状态是有货,第二个状态是出货,第三个状态是冷冻,分别记为 0 , 1 , 2 0,1,2 0,1,2。那么状态转移是这样的:
1、转移到 0 0 0,可以 0 → 0 0\to 0 00,表示昨天买入或持有,然后今天继续持有,此时边权是 0 0 0;也可以 2 → 0 2\to 0 20,昨天冷冻期,今天买入,边权是 − p [ i ] -p[i] p[i]
2、转移到 1 1 1,可以 0 → 1 0\to 1 01,表示昨天有货,今天卖了,边权是 p [ i ] p[i] p[i]
3、转移到 2 2 2,可以 1 → 2 1\to 2 12,表示昨天出货,今天冷冻一天,边权是 0 0 0;也可以 2 → 2 2\to 2 22,表示昨天冷冻,今天继续不操作,边权也是 0 0 0
一路递推到最后一天即可,最后返回三个状态结尾的cash最大值。题目隐含最后一天一定要卖,所以直接比较状态 1 1 1 2 2 2即可。代码如下:

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        
        int len = prices.length;
        int[] buy = new int[len], sell = new int[len], cool = new int[len];
        // 第0天有货的话,cash是负的
        buy[0] = -prices[0];
        for (int i = 1; i < len; i++) {
            buy[i] = Math.max(buy[i - 1], cool[i - 1] - prices[i]);
            sell[i] = buy[i - 1] + prices[i];
            cool[i] = Math.max(cool[i - 1], sell[i - 1]);
        }
        
        return Math.max(sell[len - 1], cool[len - 1]);
    }
}

时空复杂度 O ( n ) O(n) O(n)

法2:状态机,从asset角度考虑。状态定义同上,第一个状态是有货,第二个状态是出货,第三个状态是冷冻,分别记为 0 , 1 , 2 0,1,2 0,1,2。状态转移是一样的,但边权会发生变化:
1、转移到 0 0 0,可以 0 → 0 0\to 0 00,表示昨天买入或持有,然后今天继续持有,此时边权是 p [ i ] − p [ i − 1 ] p[i]-p[i-1] p[i]p[i1](股票价格变了,导致资产变化);也可以 2 → 0 2\to 0 20,昨天冷冻期,今天买入,边权是 0 0 0(资产从cash的形式变为了股票形式,但资产价值没有变);
2、转移到 1 1 1,可以 0 → 1 0\to 1 01,表示昨天有货,今天卖了,边权是 p [ i ] − p [ i − 1 ] p[i]-p[i-1] p[i]p[i1]
3、转移到 2 2 2,可以 1 → 2 1\to 2 12,表示昨天出货,今天冷冻一天,边权是 0 0 0;也可以 2 → 2 2\to 2 22,表示昨天冷冻,今天继续不操作,边权也是 0 0 0
最后要返回状态 2 2 2 3 3 3,以及状态 1 1 1减去最后一天股价三者的最大值(状态 1 1 1表示持有股票,但最后一天要变现的)。代码如下:

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        
        int len = prices.length;
        int[] buy = new int[len], sell = new int[len], cool = new int[len];
        for (int i = 1; i < len; i++) {
            buy[i] = Math.max(buy[i - 1] + prices[i] - prices[i - 1], cool[i - 1]);
            sell[i] = buy[i - 1] + prices[i] - prices[i - 1];
            cool[i] = Math.max(cool[i - 1], sell[i - 1]);
        }
        
        return Math.max(Math.max(sell[len - 1], cool[len - 1]), buy[len - 1] - prices[len - 1]);
    }
}

时空复杂度一样。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值