最佳买卖股票时机含冷冻期

首先我们定义$dp[i]$表示第$i$天结束以后总的收益,因为含有冷冻期,所以我们定义三种状态:
- $dp[i][0]$:第$i$天结束以后,持有一支股票,即当天进行买入操作或者第$i-1$天持有股票然后在第$i$天什么都没操作。
 - $dp[i][1]$:第$i$天结束以后,不持有股票,且进入冷冻期,即当天进行卖出操作。
 - $dp[i][2]$:第$i$天结束以后,不持有股票,也不进入冷冻期,即当天什么都没操作。
 
状态转移方程如下:
- 对于$dp[i][0]$,第$i$天的收益有两种情况,第一种是什么都没操作,第二种是当天进行买入操作。
 
$$
dp[i][0] = max(dp[i-1][0],dp[i-1][2]-prices[i])
$$
- 对于$dp[i][1]$,第$i$天的收益只有一种情况,就是卖出股票。
 
$$
dp[i][1] = dp[i-1][0]+prices[i]
$$
- 对于$dp[i][2]$,第$i$天的收益有两种情况,第一种是第$i-1$天就是第三种状态,且第$i$天什么都没操作,第二种是冷冻期结束。
 
$$
dp[i][2] = max(dp[i-1][1],dp[i-1][2])
$$
最后的结果应该是:
$$
max(dp[n-1][0],dp[n-1][1],dp[n-1][2])
$$
实际上不用比较$dp[n-1][0]$,应该如果在最后一天还持有股票,那么显然没有任何意义,所以只需要比较$dp[n-1][1]$和$dp[n-1][2]$就可以了。
第0天的情况为边界条件:
- $dp[0][0] = -prices[0]$
 - $dp[0][1]=0$
 - $dp[0][2]=0$
 
1 | /* | 
2 |  * @lc app=leetcode.cn id=309 lang=java | 
3 |  * | 
4 |  * [309] 最佳买卖股票时机含冷冻期 | 
5 |  */ | 
6 | |
7 | // @lc code=start | 
8 | class Solution { | 
9 |     public int maxProfit(int[] prices) { | 
10 |         if(prices.length == 0){ | 
11 |             return 0; | 
12 |         } | 
13 |         int n = prices.length; | 
14 |         int[][] dp = new int[n][3]; | 
15 |         dp[0][0] = -prices[0]; | 
16 |         dp[0][1] = 0; | 
17 |         dp[0][2] = 0; | 
18 |         for(int i=1; i<n; i++){ | 
19 |             dp[i][0] = Math.max(dp[i-1][0], dp[i-1][2]-prices[i]); | 
20 |             dp[i][1] = dp[i-1][0] + prices[i]; | 
21 |             dp[i][2] = Math.max(dp[i-1][1], dp[i-1][2]); | 
22 |         } | 
23 |         return Math.max(dp[n-1][1], dp[n-1][2]); | 
24 |     } | 
25 | } | 
复杂度分析:
- 时间复杂度:$O(n)$。
 - 空间复杂度:$O(n)$。
 
注意到第$i$天的状态只与第$i-1$天的状态有关,可以由此进行空间的优化。
1 | /* | 
2 |  * @lc app=leetcode.cn id=309 lang=java | 
3 |  * | 
4 |  * [309] 最佳买卖股票时机含冷冻期 | 
5 |  */ | 
6 | |
7 | // @lc code=start | 
8 | class Solution { | 
9 |     public int maxProfit(int[] prices) { | 
10 |         if(prices.length == 0){ | 
11 |             return 0; | 
12 |         } | 
13 |         int n = prices.length; | 
14 |         int dp0 = -prices[0]; | 
15 |         int dp1 = 0; | 
16 |         int dp2 = 0; | 
17 |         for(int i=1; i<n; i++){ | 
18 |             int newdp0 = Math.max(dp0, dp2-prices[i]); | 
19 |             int newdp1 = dp0 + prices[i]; | 
20 |             int newdp2 = Math.max(dp1, dp2); | 
21 |             dp0 = newdp0; | 
22 |             dp1 = newdp1; | 
23 |             dp2 = newdp2; | 
24 |         } | 
25 |         return Math.max(dp1, dp2); | 
26 |     } | 
27 | } | 
复杂度分析:
- 时间复杂度:$O(n)$。
 - 空间复杂度:$O(1)$。