309. 最佳买卖股票时机含冷冻期
给定一个整数数组
prices
,其中第prices[i]
表示第i
天的股票价格 。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]示例 2:
输入: prices = [1] 输出: 0提示:
1 <= prices.length <= 5000
0 <= prices[i] <= 1000
思路:
参考 LeetCode【评论区】题解
- 首先,定义状态转移方程的四种状态:
- A. dp[i][0]【当天不持有股票】并且也没有卖出操作:原本就不持有股票,可能前些天之前就早卖了没了 。
- B. dp[0][1]【当天不持有股票】因为<今天有卖出操作>:原本是有股票的,但是今天卖掉了就没了,所以不持有。
其中第0天,可以理解为今天买入股票,然后当天又卖出了,所以当前收益为0。 - C. dp[i][2]【当天持有股票】今天才最新买入的股票:前提是前一天没有卖出操作,不处于冷冻期。
- D. dp[i][3]【当天持有股票】并不是今天买入的股票:可能是从前一天“继承”过来的股票,一直没操作而已。
- 接着,梳理动态规划的状态转移方程逻辑:
-
a.【当天不持有股票】并且也没有卖出操作
dp[i][0] = max(dp[i-1][0], dp[i-1][1])
dp[i-1][0]:原本就一直没有股票
dp[i-1][1]:原本有但昨天刚卖了 -
b.【当天不持有股票】因为<今天有卖出操作>
dp[i][1] = max(dp[i-1][2], dp[i-1][3]) + prices[i]
dp[i-1][2]:昨天买入的股票,今天卖出
dp[i-1][3]:昨天之前早就买入的股票,今天卖出 -
c.【当天持有股票】今天才最新买入的股票
dp[i][2] = dp[i-1][0] - prices[i]
题目要求:卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
所以这里的前提:前一天不能卖出股票(不满足dp[i-1][1]),且之前不持有股票(不满足dp[i-1][2]和dp[i-1][3])
那么今天才能买入,最后再减去今天买股票的钱 prices[i] -
d.【当天持有股票】并不是今天买入的股票
dp[i][3] = max(dp[i-1][2], dp[i-1][3])
dp[i-1][2]:前一天买入的
dp[i-1][3]:前一天虽未买入但前一天之前就早早持有股票了
-
-
最后,返回结果:
return max(dp[days-1][0], dp[days-1][1])
因为买卖到最后,一定是不持有的(即使亏了,卖也比不卖强),所以应该是0和1两种状态,取较大值
时间复杂度:O(n)
空间复杂度:O(n)
// 参考 LeetCode【评论区】题解:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/solutions/181734/fei-zhuang-tai-ji-de-dpjiang-jie-chao-ji-tong-su-y/
// 题目要求:多次买卖一支股票
func maxProfit(prices []int) int {
days := len(prices)
dp := make([][]int, days)
for i := 0; i < len(prices); i++ {
dp[i] = make([]int, 4) // ABCD四种股票买卖中间状态
}
// A.【当天不持有股票】并且也没有卖出操作:原本就不持有股票,可能前些天之前就早卖了没了
dp[0][0] = 0
// B.【当天不持有股票】因为<今天有卖出操作>:原本是有股票的,但是今天卖掉了就没了,所以不持有
dp[0][1] = 0 // 第0天,可以理解为今天买入股票,然后当天又卖出了,所以当前收益为0
// C.【当天持有股票】今天才最新买入的股票:前提是前一天没有卖出操作,不处于冷冻期
dp[0][2] = -prices[0]
// D.【当天持有股票】并不是今天买入的股票:可能是从前一天“继承”过来的股票,一直没操作而已
dp[0][3] = -prices[0] // 第0天特殊情况,初始化
for i := 1; i < days; i++ {
// a.【当天不持有股票】并且也没有卖出操作
// dp[i-1][0]:原本就一直没有股票
// dp[i-1][1]:原本有但昨天刚卖了
dp[i][0] = max(dp[i-1][0], dp[i-1][1])
// b.【当天不持有股票】因为<今天有卖出操作>
// dp[i-1][2]:昨天买入的股票,今天卖出
// dp[i-1][3]:昨天之前早就买入的股票,今天卖出
dp[i][1] = max(dp[i-1][2], dp[i-1][3]) + prices[i]
// c.【当天持有股票】今天才最新买入的股票
// 题目要求:卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
// 所以这里的前提:前一天不能卖出股票(不满足dp[i-1][1]),且之前不持有股票(不满足dp[i-1][2]和dp[i-1][3])
// 那么今天才能买入,最后再减去今天买股票的钱 prices[i]
dp[i][2] = dp[i-1][0] - prices[i]
// d.【当天持有股票】并不是今天买入的股票
// dp[i-1][2]:前一天买入的
// dp[i-1][3]:前一天虽未买入但前一天之前就早早持有股票了
dp[i][3] = max(dp[i-1][2], dp[i-1][3])
}
// 因为买卖到最后,一定是不持有的(即使亏了,卖也比不卖强),所以应该是0和1两种状态,取较大值
return max(dp[days-1][0], dp[days-1][1])
}
func max(a, b int) int {
if a > b {
return a
}
return b
}