您的位置:首页 > 其它

309. Best Time to Buy and Sell Stock with Cooldown

2016-07-09 22:03 281 查看
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 = 3
transactions = [buy, sell, cooldown, buy, sell]


摘自:https://discuss.leetcode.com/topic/30431/easiest-java-solution-with-explanations/2

1. Define States

To represent the decision at index i:
buy[i]
: Max profit till index i. The series
of transaction is ending with a buy.
sell[i]
: Max profit till index i. The series
of transaction is ending with a sell.

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
.

A great explanation. I think the definitions of 
buy[i]
 and 
sell[i]
 can
be refined to these:

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.

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;
}


-------------------------------------------------------------------------------------

自己想的O(N^2)的方法。。。

对于某天来说,如果是休息,最大利润和前一天相同,否则的话要做决策,不卖的话跟前一天一样。卖的话依次看看i-1天,i-2天……的情况,

如果i-k天做了卖出操作,那么i-k+1天就要休息,最大利润就是今天价格减去[i-k+2 ,i-1]的最小值,如果i-k-1天做了卖出操作,最大利润就是今天价格减去[i-k+1 ,i-1]的最小值,如果i-k和i-k-1天都没有做卖出操作,最大利润是今天价格减去[i-k,i-1]的最小值。怎么知道哪一天是卖了的呢?另外开辟一个数组记录,dp的过程中如果第i天利润最大不是和i-1天相同,说明是卖出了的,标记这一天就行了。

public int maxProfit(int[] prices)
{
int len=prices.length;
if(len<2)
return 0;

int[] dp=new int[len];
int[] aux=new int[len];
SegmentTree2_1 sgt=new SegmentTree2_1(len);
sgt.build(1, len, 1, prices);

dp[0]=0;
dp[1]=prices[1]>prices[0]?prices[1]-prices[0]:0;

for(int i=2;i<len;i++)
{
int max=dp[i-1];
for(int j=i-2;j>=0;j--)
{

int k;
if(aux[j]==1)
k=j+2;
else if(j-1>=0&&aux[j-1]==1)
k=j+1;
else {
k=j;
}

int stepmin=(int) sgt.query(k+1, i, 1, len, 1);

max=Math.max(max, dp[j]+prices[i]-stepmin);
}
if(max!=dp[i-1])
aux[i]=1;

dp[i]=max;
}

return dp[len-1];
}

}

cl
a0da
ass SegmentTree2_1
{
private long[] ele;
int cnt=0;

public SegmentTree2_1(int maxn)
{
ele = new long[maxn << 2];
}

public void build(int l, int r, int rt,int[] arr)
{
if(arr.length<1)
return ;

if (l == r)
{
ele[rt] = arr[cnt++];
return;
}

int m = (l + r) >> 1;
build(l, m, rt << 1,arr);
build(m + 1, r, rt << 1 | 1,arr);
PushUP(rt);
}

private void PushUP(int rt)
{
ele[rt] = Math.min(ele[rt << 1] , ele[rt << 1 | 1]);
}

public long query(int L, int R, int l, int r, int rt)
{
if (L <= l && r <= R)
return ele[rt];
int m = (l + r) >> 1;
long ret = Integer.MAX_VALUE;
if (L <= m)
ret = Math.min(ret,query(L, R, l, m, rt << 1));
if (R > m)
ret = Math.min(ret,query(L, R, m + 1, r, rt << 1 | 1));
return ret;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: