309.最佳买卖股票时机含冷冻期
题目:
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 示例:
输入: [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
解析:
假设我们用f(i)表示第i天结束后的收益,根据题目所说,我们是多次买卖一支股票,并且卖出股票后有1天的冷冻期,因此我们会有三种不同的情况:
- 持有股票,记为f(i)[0]
- 未持有股票,处于冷冻期,记为f(i)[1]
- 未持有股票,未处冷冻期,记为f(i)[2]
我们接着分析:
- 如果第i天是情况1,那么第i-1天要么是情况1,持有股票并第i天未卖出,要么是情况3,未持有股票且未处冷冻期并且在第i天买入,所以f(i)[0] = Math.max(f(i-1)[0], f(i-1)[2] - prices[i]);
- 如果第i天是情况2,那么第i-1天是情况1,持有股票并第i天卖出股票,所以f(i)[1] = f(i-1)[0] + prices[i];
- 如果第i天是情况3,那么第i-1天是情况2,处于冷冻期,要么是情况3,未持有股票且未处冷冻期并且在第i天未买入,所以f(i)[2] = Math.max(f(i-1)[1], f(i-1)[2] );
经以上分析,我们得出:
f(i)[0] = Math.max(f(i-1)[0], f(i-1)[2] - prices[i])
f(i)[1] = f(i-1)[0] + prices[i]
f(i)[2] = Math.max(f(i-1)[1], f(i-1)[2] )
f(i)只与f(i-1)有关系,我们可以用滚动数组来简化内存。
最后我们在考虑一下边界值,最后一天,股票直接卖掉,做到利益最大化。
代码如下:
public int maxProfit(int[] prices) {
if (prices.length == 0) {
return 0;
}
int n = prices.length;
int f0 = -prices[0];
int f1 = 0;
int f2 = 0;
for (int i = 1; i < n; ++i) {
int newf0 = Math.max(f0, f2 - prices[i]);
int newf1 = f0 + prices[i];
int newf2 = Math.max(f1, f2);
f0 = newf0;
f1 = newf1;
f2 = newf2;
}
return Math.max(f1, f2);
}
复杂度分析
-
时间复杂度:O(n),其中 n 为数组prices 的长度。
-
空间复杂度:O(1)。只用到了固定的空间。