1. 问题描述:
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown
2. 思路分析:
这道题目属于经典的状态机dp的问题(题目中存在多个状态),对于状态机dp的问题我们需要分析清楚题目的状态,然后对状态进行转移即可,分析题目可以知道题目存在三种状态,分析是进入冷冻期、已买入、今天卖出三种状态,根据题目的描述进行状态的转移图如下(理清楚状态之间的转移剩下来的就好办了,根据图写出具体的代码即可),我们需要声明数组或者列表dp来记录转移过程的值,因为使用的是python语言所以需要声明一个二维列表dp,其中第一维的长度为n = len(nums)表示天数,第二维的长度为3,其中的0,1,2分别对应三种状态,dp[i][j]表示的意思是前i天对应状态为j的最大利润,一开始的时候初始化第0天的冷冻期与已买入的状态,然后根据状态转移图进行状态转移即可,其实可以发现每一维都存在三种状态所以递推到最后一天状态的时候实际上是尝试了所有可能的状态,有点像暴力枚举的,只是这里在枚举的时候有选择性的记忆所以不用搜索全部的可能性(可以看出成是暴力枚举的优化)。
3. 代码如下:
from typing import List
class Solution:
# 其实每一维都存在三个状态所以dp列表其实是在尝试所有可能的状态
def maxProfit(self, prices: List[int]) -> int:
inf = 10 ** 8
n = len(prices)
# 初始化二维列表值
dp = [[-inf] * 3 for i in range(n)]
# 初始化第一天的第一个和第二个状态
dp[0][0] = 0
dp[0][1] = -prices[0]
for i in range(1, n):
dp[i][0] = max(dp[i - 1][0], dp[i - 1][2])
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])
dp[i][2] = dp[i - 1][1] + prices[i]
return max(dp[n - 1][0], dp[n - 1][1], dp[n - 1][2])