【算法刷题有感】LeetCode-309. 最佳买卖股票时机含冷冻期

136 阅读2分钟

深度理解代替单纯记忆

题目地址:309. 最佳买卖股票时机含冷冻期

做提建议: 建议先做714. 买卖股票的最佳时机含手续费

求解思路

比没有冷冻期的股票问题要难不少。上一题是两个状态:持有股票和不持有股票

该题目要分成四个状态,知道分为四个状态并不重要,知道这四种状态如何产生的才重要

笔者在做本题时,会自然的使用持有、不持有两种状态尝试解决,结果在思考解题思路过程中,发现动态规划的状态表填写起来特别费劲。这就说明这两种状态很难完整准确且清晰的描述该问题

那如何才能找到完整清晰的思路呢?

需将该问题进行拆分,就本题而言就是将所有的“操作”(买入、卖出、什么都不做)列出来

重点关注1. 什么情况下可以执行哪些操作;2. 执行完这些操作后的情况是什么样的

其实如果你有学习过设计模式中的状态模式,就更容易理解了---一个状态经过某个操作后会转为另一种状态

上面要关注的两个问题,其实就是某状态下可以做哪些操作,做了某个操作后可以到达哪一个新状态

我用这种思考方式,就逐渐摸索出来需要四种状态(当然,一开始只想到了三种,后来填状态表时发现三种不够)

操作1:买入;操作2:卖出;操作3:什么都不做

状态1:持有股票状态(该状态可以通过前一天的状态1+操作3得出;也可以昨天状态2、4+操作1得出)

状态2:普通不持有股票状态(昨天的状态2+操作3;昨天状态4+操作3)

状态3:今天卖了股票,今天白天结束后,进入冷冻期(昨天状态1+操作2)

状态4:今天是冷冻期的一天,结束后就解封了(昨天状态3+操作3)

多说一句,可以看出来,状态2、3、4其实都是不持有股票的状态,但必须细分出来,否则无法进行状态转移

func maxProfit(_ prices: [Int]) -> Int {
    let count = prices.count
    var dp = Array(repeating: Array(repeating: 0, count: 4), count: count)
    dp[0][0] = -prices[0]

    for i in 1..<count {
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
        dp[i][0] = max(dp[i][0], dp[i-1][3] - prices[i])

        dp[i][1] = max(dp[i-1][1], dp[i-1][3])

        dp[i][2] = dp[i-1][0] + prices[i]

        dp[i][3] = dp[i-1][2]
    }
    var maxValue = Int.min

    for i in 0..<4 {

        if dp[count-1][i] > maxValue {
            maxValue = dp[count-1][i]
        }
    }
    return maxValue
}

收获

求解思路中有提到

  1. 将问题抽象为几个完整、准确、清晰的状态过程很重要,本质是将问题抽象为计算机容易理解和解决的模型
  2. 参考状态模式,按照操作、状态将问题拆分,对解决问题很有帮助