文章目录
- Tag
- 题目来源
- 题目解读
- 解题思路
- 方法一:动态规划+空间优化
- 写在最后
Tag
【动态规划】【数组】【2023-10-05】
题目来源
309. 买卖股票的最佳时机含冷冻期
题目解读
这是股票系列问题的第五篇了,要求求出买卖股票的最佳时期以获得最大的利润,本题的关键在于:你卖出股票后无法在当天买入股票,需要等待一天。
解题思路
方法一:动态规划+空间优化
状态
我们使用 f[i]
表示第 i
天结束后的累计最大收益。因为我们最多同时买入一只股票并且有股票冷冻期的限制,所以会有以下三种不同的状态:
- 我们目前持有一只股票,对应的累计最大收益用
f[i][0]
表示; - 我们目前不持有任何一只股票,并处于冷冻期中,对应的累计最大收益用
f[i][1]
表示; - 我们目前不持有任何一只股票,不处于冷冻期中,对应的累计最大收益用
f[i][2]
表示。
转移关系
对于以上的三种状态,我们有这样的转移关系:
- 对于
f[i][0]
即我们第i
天持有一只股票,这可以是第i-1
天手中就持有的,对用的状态为f[i-1][0]
;或者是第i
天买入的,那么第i-1
就不能持有股票并且不处于冷冻期中,对用的状态为f[i-1][2]
,此时还要扣除买prices[i]
股票的费用。因此,该情况下的状态转移方程为:
f [ i ] [ 0 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 2 ] − p r i c e s [ i ] ) f[i][0] = max(f[i-1][0], f[i-1][2] - prices[i]) f[i][0]=max(f[i−1][0],f[i−1][2]−prices[i])
- 对于
f[i][1]
即我们第i
天不持有任何一只股票且处于冷冻期,说明我们第i
天卖出了一只股票,也就说明第i-1
天我们必须持有一只股票,对应的状态为f[i-1][0]
加上股票卖出的收益。因此,此时的转移关系为:
f [ i ] [ 1 ] = f [ i − 1 ] [ 0 ] + p r i c e s [ i ] f[i][1] = f[i-1][0] + prices[i] f[i][1]=f[i−1][0]+prices[i]
- 对于
f[i][2]
即我们第i
天不持有任何一只股票,不处于冷冻期中,说明当天没有进行任何操作,那么第i-1
天也就不会持有任何股票;第i-1
天不持有任何一只股票又会有两种状态。因此,此时的转移关系为:
f [ i ] [ 2 ] = m a x ( f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 1 ] ) f[i][2] = max(f[i-1][1], f[i-1][1]) f[i][2]=max(f[i−1][1],f[i−1][1])
base case
f[0][0] = -prices[0]
,第 0
天持有股票,那么只能在第 0
天买入;
f[0][1] = 0
,f[0][2] = 0
,我们不持有股票,那么收益为 0
。
最后返回
最后返回的是 max(f[n-1][0], f[n-1][1], f[n-1][2])
,即第 n-1
天交易结束后三种状态的最大值,但是我们知道卖光手中的股票一定比手中还留有股票可以获得更大的利润,因此最后返回 max(f[n-1][1], f[n-1][2])
。
实现代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<int>> f(n, vector<int>(3, 0));
f[0][0] = -prices[0];
for (int i = 1; i < n; ++i) {
f[i][0] = max(f[i-1][0], f[i-1][2] - prices[i]);
f[i][1] = f[i-1][0] + prices[i];
f[i][2] = max(f[i-1][1], f[i-1][2]);
}
return max(f[n-1][1], f[n-1][2]);
}
};
空间优化
换一种想法,我们要通过买卖股票获得最大的利润,那么我们肯定希望手中的钱越多越好。我们仅使用三个变量来维护三种交易状态后的手中剩余的最大钱数:
buy
:一天交易结束后手中还有股票的最大收益,初始化为-prices[0]
;sell
:一天交易结束后手中没有股票的最大收益,,初始化为0
;sell_pre
:用来记录前一天卖出股票后手中剩余的最大钱数,初始为0
;如果没有冷冻期,那么本题就退化成 122. 买卖股票的最佳时机 II,此时我们可以在第i
天卖了股票之后又买当天的股票。但是,在增加了冷冻期的本题中,卖了股票之后就不能再买当天的股票了,需要等到第二天才能买,因此需要sell_pre
。
注意对 sell_pre
的理解。
实现代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int buy = -prices[0];
int sell_pre = 0, sell = 0;
for (int p : prices) {
buy = max(buy, sell_pre - p);
sell_pre = sell;
sell = max(sell, buy + p);
}
return sell;
}
};
复杂度分析
时间复杂度:
O
(
n
)
O(n)
O(n),
n
n
n 为数组 prices
的长度。
空间复杂度: O ( n ) O(n) O(n),使用的额外空间为记录每天交易结束后的状态,占用的空间为 O ( 3 × n ) O(3 \times n) O(3×n)。空间优化后的空间复杂度为 O ( 1 ) O(1) O(1)。
写在最后
买卖股票系列题目
题目 | 解答 |
---|---|
121. 买卖股票的最佳时机 | 【面试经典150】买卖股票的最佳时机 |
122. 买卖股票的最佳时机 II | 【面试经典150】买卖股票的最佳时机 II |
123. 买卖股票的最佳时机 III | 【每日一题】买卖股票的最佳时机 III |
188. 买卖股票的最佳时机 IV | 【每日一题】买卖股票的最佳时机 IV |
714. 买卖股票的最佳时机含手续费 | 【每日一题】买卖股票的最佳时机含手续费 |
如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。
最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。