步骤一、确定状态:
确定dp数组及下标含义
dp[i] 表示的是在第i天可以获取的最大利润,每天会有持有股票和不持有股票两种状态,这个是 第二维度,还是用0和1表示。 而对于每一种状态,这里还会有交易次数的记录0次or1次or2次, 这个是第三维度。所以dp[天数][当前是否持股][卖出的次数]
步骤二、推断状态方程:
dp[i][0],也就是没有持股的状态,会有三次交易次数讨论:
dp[i][0][0]: 表示的是当前未持股, 且交易了0次,说明目前是从未进行买卖, 那么此时最 大利润为 dp[i][0][0]=0
dp[i][0][1]: 表示的是当前未持股,且有1次交易时最大利润,卖出过1次股票,在第1次卖 出的状态,那么它的状态依然来自两个方向推导过来的,可能是今天卖出去的,也可能是 延续了昨天的状态:
如果是延续了昨天的状态, 那么最大利润就是dp[i-1][0][1]
如果是今天刚卖出去的, 说明昨天是持有股票的,也就是昨天没有卖出(之前交易了0次), 那么最大利润就是dp[i-1][1][0]+prices[i]
所以这时候要选最大, dp[i][0][1] = max(dp[i-1][0][1], dp[i-1][1][0]+prices[i])
dp[i][0][2]: 表示的是当前未持股, 且有2次交易股票时最大利润,这是第二次卖出的状 态,状态依然是两个方向推导过来,可能是今天卖出去的,也可能延续了前面的状态:
如果是延续了昨天的状态, 那么最大利润就是dp[i-1][0][2]
如果是今天刚卖出去的, 说明昨天是持有股票的,但是此时已经交易过了1次了,那么 最大利润就是dp[i-1][1][1]+prices[i]
所以这时候要选最大, dp[i][0][2] = max(dp[i-1][0][2], dp[i-1][1][1]+prices[i])
然后是dp[i][1], 也就是持股状态,依然会有三次次交易讨论:
dp[i][1][0]: 表示的是当前持股,且有0次股票交易时的利润,也就是第一次买入的状态, 那么它的状 态依然来自两个方向推导过来的,可能是今天刚买的,也可能是延续了昨天的状态如果是延续了昨天 的状态, 那么最大利润就是dp[i-1][1][0]
如果是今天刚买的, 说明昨天是没有股票的,那么最大利润就是dp[i-1][0][0]-prices[i] 所以这时候要选最大, dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][0][0]-prices[i])
dp[i][1][1]: 表示的是当前持股,且有1次股票交易时的利润,也就是第二次买入的状态,那么它的状 态依然来自两个方向推导过来的,可能是今天刚买的,也可能是延续了昨天的状态如果是延续了昨天 的状态, 那么最大利润就是dp[i-1][1][1]
如果是今天刚买的, 说明昨天是没有股票的,那么最大利润就是dp[i-1][0][1]-prices[i] 所以这时候要选最大, dp[i][1][1] = max(dp[i-1][1][1], dp[i-1][0][1]-prices[i])
dp[i][1][2]: 表示的是当前持股, 且有2次股票交易时的利润,这个情况是不可能出现的,因为进行 完两笔交易就不能交易了呀,这时候可以给个最小的负数即可。
步骤三、规定初始条件:
初始条件:
全局初始化为0, 然后第0天的所有状态必须都初始化出来: dp[0][0][0] = 0: 开始啥也没干, 利润0
dp[0][0][1] = float("-inf"): 第0天没有持有股票,且进行了一次交易,这种情况不 可能
dp[0][0][2] = float("-inf"):第0天没有持有股票,且进行了两次交易,这种情况依 然不可能
dp[0][1][0] = -prices[0]: 第0天持有股票,且进行了0次交易,这是第一次买入,利 润-prices[0]
dp[0][1][1] = float("-inf"): 第0天持有股票,且进行了1次交易,这种情况不可能 dp[0][1][2] = float("-inf"): 第0天持有股票,且进行了2次交易,这种情况不可能
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 异常判断
if len(prices) == 1:
return 0
# dp[天数][当天是否持股][卖出的次数] 最大利润
# 当天是否持股: 0 or 1
# 卖出的次数: 0、1、2
dp = [[[0 for _ in range(3)] for _ in range(2)] for _ in range(len(prices))]
dp[0][0][0], dp[0][0][1], dp[0][0][2] = 0, float("-inf"), float("-inf")
dp[0][1][0], dp[0][1][1], dp[0][1][2] = -prices[0], float("-inf"), float("-inf")
for i in range(1, len(prices)):
# 不持有股票
dp[i][0][0] = 0
dp[i][0][1] = max(dp[i-1][0][1], dp[i-1][1][0] + prices[i]) # 第一次卖出
dp[i][0][2] = max(dp[i-1][0][2], dp[i-1][1][1] + prices[i]) # 第二次卖出
# 持有股票
dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][0][0] - prices[i]) # 第一次买入
dp[i][1][1] = max(dp[i-1][1][1], dp[i-1][0][1] - prices[i]) # 第二次买入
dp[i][1][2] = float("inf") # 第三次买入不可能
# 返回最后一天未持有股票的值
return max(dp[-1][0])