题目地址:
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
0→0,表示昨天买入或持有,然后今天继续持有,此时边权是
0
0
0;也可以
2
→
0
2\to 0
2→0,昨天冷冻期,今天买入,边权是
−
p
[
i
]
-p[i]
−p[i];
2、转移到
1
1
1,可以
0
→
1
0\to 1
0→1,表示昨天有货,今天卖了,边权是
p
[
i
]
p[i]
p[i];
3、转移到
2
2
2,可以
1
→
2
1\to 2
1→2,表示昨天出货,今天冷冻一天,边权是
0
0
0;也可以
2
→
2
2\to 2
2→2,表示昨天冷冻,今天继续不操作,边权也是
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
0→0,表示昨天买入或持有,然后今天继续持有,此时边权是
p
[
i
]
−
p
[
i
−
1
]
p[i]-p[i-1]
p[i]−p[i−1](股票价格变了,导致资产变化);也可以
2
→
0
2\to 0
2→0,昨天冷冻期,今天买入,边权是
0
0
0(资产从cash的形式变为了股票形式,但资产价值没有变);
2、转移到
1
1
1,可以
0
→
1
0\to 1
0→1,表示昨天有货,今天卖了,边权是
p
[
i
]
−
p
[
i
−
1
]
p[i]-p[i-1]
p[i]−p[i−1];
3、转移到
2
2
2,可以
1
→
2
1\to 2
1→2,表示昨天出货,今天冷冻一天,边权是
0
0
0;也可以
2
→
2
2\to 2
2→2,表示昨天冷冻,今天继续不操作,边权也是
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]);
}
}
时空复杂度一样。