深度理解代替单纯记忆
题目地址: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
}
收获
求解思路中有提到
- 将问题抽象为几个完整、准确、清晰的状态过程很重要,本质是将问题抽象为计算机容易理解和解决的模型
- 参考状态模式,按照操作、状态将问题拆分,对解决问题很有帮助