leetcode 309.Best Time to Buy and Sell Stock with Cooldown (time : O(n))

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]

还是买卖股票的问题,但是这次不能卖了隔天就买,卖了之后要停一天才能再买入下一个。
但是如果买了,隔天是可以卖的。

思路:
前面123, 188题是用dp保存前面的profit,然后今天选择交易或不交易。

现在如果还用dp保存profit,因为买入的话要cool down一天,所以要参考dp[i - 2],但是不能确定在dp[i - 2]的时候是不是手上有股票,如果有,就不能在它的基础上再买。
所以dp[i] 不一定能在dp[i - 2]的基础上交易

同理,如果dp[i -1]的时候手上持有股票,在dp[i]的时候是可以卖的。
所以dp[i] 有时是可以在dp[i - 1]的基础上交易的

上述思路具有不确定性,所以要转换思路,因为今天能不能交易取决于前面手上是否持有股票,如果有,那么可以直接卖掉,不用 cool down一天。如果没有,就要考虑cool down一天的条件,只能参考两天前的profit。

所以定义两个dp数组,一个是持有股票的dp:hold[n], 一个是手上没有股票的dp:unhold[n]

边界条件:
hold[0] = -prices[0],
因为在0处如果持有股票,就要用prices[0]的价钱买入,profit就是-prices[0]
hold[1] = max(-prices[0], -prices[1])
因为不能同时买入两个股票,必须卖了才能买,而第二天是不能同时卖掉第一个再买入第二个的,不满足cool down,所以只能要么买prices[0], 要么买prices[1], 选其中profit较大的
unhold[0] = 0, 因为不买,没有profit

state变化:
hold[i]: hold表示持有,即买入。如果在i处不买,就保留hold[i - 1],
如果买入,那么前提是i-2处已经卖出,即unhold[i - 2]
profit = unhold[i - 2] - prices[i]
取买和不买的较大profit:max(hold[i - 1], unhold[i - 2] - prices[i])

unhold[i]: 不持有股票,即卖出。i处不卖,则保留unhold[i - 1]
i处卖掉,hold[i - 1] + prices[i], 取较大值

最后要取最大收益,也就是手上是没有股票的状态,unhold[n - 1]
(手上还有股票说明还有一部分收益没变现,肯定不是最大的)

   //1ms
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        
        int[] hold = new int[prices.length];
        int[] unhold = new int[prices.length];
        
        hold[0] = -prices[0];      
        
        for (int i = 1; i < prices.length; i++) {
            if (i == 1) {
                hold[1] = Math.max(-prices[0], -prices[1]);
            } else {
                hold[i] = Math.max(hold[i - 1], unhold[i - 2] - prices[i]);
            }
            unhold[i] = Math.max(unhold[i - 1], hold[i - 1] + prices[i]);
        }
        
        return unhold[prices.length - 1];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值