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

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【评论区】题解
LeetCode 309. 最佳买卖股票时机含冷冻期_第1张图片

  • 首先,定义状态转移方程的四种状态:
    • 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
}

你可能感兴趣的:(#,LeetCode,leetcode,动态规划)