leetcode 309. Best Time to Buy and Sell Stock with Cooldown

来源:互联网 发布:python经纬度画轨迹图 编辑:程序博客网 时间:2024/06/07 02:39

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:

prices = [1, 2, 3, 0, 2]maxProfit = 3transactions = [buy, sell, cooldown, buy, sell]

这道题我一开始用的递归+memory做的,居然TLE了。然后我改成DP做,才AC了,但是发现只beat了1%的人。

dp[ i ] 存储了从 i ~ prices.length 的时间段内的最大收益。i 从大到小来慢慢算出 dp[i]。

public int maxProfit(int[] prices) {int n=prices.length;if(n==0){return 0;}int[] dp=new int[n];dp[n-1]=0;for(int begin=n-2;begin>=0;begin--){int maxCount=0;//以begin为起点时间段内的最大收益for(int end=begin+1;end<n;end++){//依次遍历begin后面的时间点int count=0;if(prices[end]<=prices[begin]){count=dp[end];}else{//如果 end股票值>begin股票值,说明可以在begin买入,end抛出if(end+2<n){count=prices[end]-prices[begin]+dp[end+2];}else{count=prices[end]-prices[begin];}}if(count>maxCount){maxCount=count;}}dp[begin]=maxCount;}return dp[0];}
大神们用了有限状态机模型来解决。

这个问题的三个状态分别是: buysellrest. 这里 rest 意味着在当天没有任何交易。这个有限状态机有可能在任意的这三个状态中停止。我们可以简化为2个状态:buysellbuy状态指当前最后一笔交易是买入,比如[0,1,2],在0时买入,在1时不交易,此时1的状态仍然是buy状态。sell状态指当前最后一笔交易是卖出,比如[0,2,1],在0时买入,2时卖出,此时2和1的状态都是sell状态。

这里显示了它们之间的关系。

第 i 天的状态为buy状态,有两种可能:“在 i-2 天状态为卖出,在第 i 天买入”(单单仅 第 i-1 天状态为卖出 不够,必须是第 i-2 天状态也是卖出 才行“)或者 “在第 i-1 天状态为买入,第 i 天保持不变”。

第 i 天的状态为sell状态,有两种可能:“在 i-1 天状态为买入,在第 i 天卖出” 或者 “在第 i-1 天状态为卖出,第 i 天保持不变”。

buy[i] = max(sell[i-2]-price, buy[i-1])sell[i] = max(buy[i-1]+price, sell[i-1])

考虑到day  i 依赖于day i-1 和 i-2 的状态,我们可以进一步简化我们的解决方案,

  • b2, b1, b0 来表达 buy[i - 2], buy[i - 1], buy[i]
  • 让 s2, s1, s0 来表达 sell[i - 2], sell[i - 1], sell[i]

因此公式转化为:

b0 = Math.max(b1, s2 - prices[i]);s0 = Math.max(s1, b1 + prices[i]);

我们定义i = 0的初始状态

  • 可以为买入状态 ,在 i = 0 处买入,收益为 -prices[0].
  • 可以为卖出状态,在 i = 0 处为卖出状态,意思就是不做任何交易,收益为 0.
 因为最后一天的状态不可能是买入,只可能是卖出状态,因此返回结果是 s0 。

 这是代码:

public int maxProfit(int[] prices) {    if(prices == null || prices.length <= 1) return 0;      int b0 = -prices[0], b1 = b0;    int s0 = 0, s1 = 0, s2 = 0;     for(int i = 1; i < prices.length; i++) {    b0 = Math.max(b1, s2 - prices[i]);    s0 = Math.max(s1, b1 + prices[i]);    b1 = b0; s2 = s1; s1 = s0;     }    return s0;}
如果还是不懂,可以看大神的原版英文解释哦:

1. Define States

To represent the decision at index i:

  • buy[i] : Maximum profit which end with buying on day i or end with buying on a day before i and takes rest until the day i since then.
  • sell[i] : Maximum profit which end with selling on day i or end with selling on a day before i and takes rest until the day i since then.

To clarify:

  • Till index i, the buy / sell action must happen and must be the last action. It may not happen at index i. It may happen at i - 1, i - 2, ... 0.
  • In the end n - 1, return sell[n - 1]. Apparently we cannot finally end up with a buy. In that case, we would rather take a rest at n - 1.
  • For special case no transaction at all, classify it as sell[i], so that in the end, we can still return sell[n - 1]. Thanks @alex153 @kennethliaoke @anshu2.

2. Define Recursion

  • buy[i]: To make a decision whether to buy at i, we either take a rest, by just using the old decision at i - 1, or sell at/before i - 2, then buy at i, We cannot sell at i - 1, then buy at i, because of cooldown.
  • sell[i]: To make a decision whether to sell at i, we either take a rest, by just using the old decision at i - 1, or buy at/before i - 1, then sell at i.

So we get the following formula:

buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i]);   sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);

3. Optimize to O(1) Space

DP solution only depending on i - 1 and i - 2 can be optimized using O(1) space.

  • Let b2, b1, b0 represent buy[i - 2], buy[i - 1], buy[i]
  • Let s2, s1, s0 represent sell[i - 2], sell[i - 1], sell[i]

Then arrays turn into Fibonacci like recursion:

b0 = Math.max(b1, s2 - prices[i]);s0 = Math.max(s1, b1 + prices[i]);

4. Write Code in 5 Minutes

First we define the initial states at i = 0:

  • We can buy. The max profit at i = 0 ending with a buy is -prices[0].
  • We cannot sell. The max profit at i = 0 ending with a sell is 0.

Here is my solution. Hope it helps!

public int maxProfit(int[] prices) {    if(prices == null || prices.length <= 1) return 0;      int b0 = -prices[0], b1 = b0;    int s0 = 0, s1 = 0, s2 = 0;     for(int i = 1; i < prices.length; i++) {    b0 = Math.max(b1, s2 - prices[i]);    s0 = Math.max(s1, b1 + prices[i]);    b1 = b0; s2 = s1; s1 = s0;     }    return s0;}


阅读全文
0 0
原创粉丝点击