1. :买卖股票的最佳时机III
题目链接: 123. 买卖股票的最佳时机 III - 力扣(LeetCode)
应用条件:
难点:
# 确定dp数组(dp table)以及下标的含义:dp[i][j]表示第i天所有的最大金额,j有五个状态表示的都是第i天所有的最多现金 dp[i][0]表示没操作,dp[i][1]表示在第i天持有第一次买入的股票的所有的最多现金,do[i][2]表示第i天已经卖出第一支股票所有的最多现金,dp[i][3]表示在第i天持有第二次买入的股票所有的最多现金,do[i][2]表示第i天已经卖出第二支股票的所有的最多现金,
# 确定递推公式: dp[i][0] = dp[i-1][0], dp[i][1] = max(dp[i-1][0]-prices[i],dp[i-1][1]),dp[i][2] = max(dp[i-1][1]+prices[i],dp[i-1][2]),dp[i][3] = max(dp[i-1][2]-prices[i],dp[i-1][3]),dp[i][4] = max(dp[i-1][3]+prices[i],dp[i-1][4])
# dp数组如何初始化: dp[0][0]=0, dp[0][1]=-prices[0], dp[0][2]=0, dp[0][3]=-prices[0], dp[0][4]=0
# 确定遍历顺序: for i in range(1,len(nums))
个人错误:
还是一旦涉及到多个状态,dp数组很难想出来
思路:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) == 0 or len(prices) == 1:
return 0
dp = [[-float(inf)]*5 for i in range(len(prices))]
dp[0][0] = 0
dp[0][1]=-prices[0]
dp[0][2]=0
dp[0][3]=-prices[0]
dp[0][4]=0
for i in range(1,len(prices)):
dp[i][0] = dp[i-1][0]
dp[i][1] = max(dp[i-1][0]-prices[i],dp[i-1][1])
dp[i][2] = max(dp[i-1][1]+prices[i],dp[i-1][2])
dp[i][3] = max(dp[i-1][2]-prices[i],dp[i-1][3])
dp[i][4] = max(dp[i-1][3]+prices[i],dp[i-1][4])
return dp[len(prices)-1][4]
2. :买卖股票的最佳时机IV
题目链接: 188. 买卖股票的最佳时机 IV - 力扣(LeetCode)
应用条件:
难点:
# 确定dp数组(dp table)以及下标的含义:dp[i][j]表示第i天所有的最大金额,j有五个状态表示的都是第i天所有的最多现金 dp[i][0]表示没操作,dp[i][1]表示在第i天持有第一次买入的股票的所有的最多现金,do[i][2]表示第i天已经卖出第一支股票所有的最多现金,dp[i][3]表示在第i天持有第二次买入的股票所有的最多现金,do[i][2]表示第i天已经卖出第二支股票的所有的最多现金,...直到2k
# 确定递推公式: dp[i][奇数] = max(dp[i-1][奇数-1]-prices[i],dp[i-1][奇数]),dp[i][偶数] = max(dp[i-1][偶数-1]+prices[i],dp[i-1][偶数])
# dp数组如何初始化: dp[0][0] = 0
# for j in range(1,2*k+1,2):
# dp[0][j]=-prices[0]
# dp[0][j+1]=0
# 确定遍历顺序:for i in range(1,len(prices)): for j in range(1,2*k+1,2):
个人错误:
思路:
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
if len(prices) == 0 or len(prices) == 1:
return 0
dp = [[-float(inf)]*(2*k +1) for i in range(len(prices))]
dp[0][0] = 0
for j in range(1,2*k+1,2):
dp[0][j]=-prices[0]
dp[0][j+1]=0
for i in range(1,len(prices)):
dp[i][0] = dp[i-1][0]
for j in range(1,2*k+1,2):
dp[i][j] = max(dp[i-1][j-1]-prices[i],dp[i-1][j])
dp[i][j+1] = max(dp[i-1][j]+prices[i],dp[i-1][j+1])
print(dp)
return dp[len(prices)-1][2*k]
3. :最佳买卖股票时机含冷冻期
题目链接: 309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode)
应用条件:
难点:
# 确定dp数组(dp table)状态一:持有股票状态(今天买入股票,或者是之前就买入了股票然后没有操作,一直持有)不持有股票状态,这里就有两种卖出股票状态
# 状态二:保持卖出股票的状态(两天前就卖出了股票,度过一天冷冻期。或者是前一天就是卖出股票状态,一直没操作)
# 状态三:今天卖出股票
# 状态四:今天为冷冻期状态,但冷冻期状态不可持续,只有一天!
# 确定递推公式:
# 达到买入股票状态(状态一)即:dp[i][0],有两个具体操作:
# 操作一:前一天就是持有股票状态(状态一),dp[i][0] = dp[i - 1][0]
# 操作二:今天买入了,有两种情况
# 前一天是冷冻期(状态四),dp[i - 1][3] - prices[i]
# 前一天是保持卖出股票的状态(状态二),dp[i - 1][1] - prices[i]
# 那么dp[i][0] = max(dp[i - 1][0], dp[i - 1][3] - prices[i], dp[i - 1][1] - prices[i]);
# 达到保持卖出股票状态(状态二)即:dp[i][1],有两个具体操作:
# 操作一:前一天就是状态二
# 操作二:前一天是冷冻期(状态四)
# dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
# 达到今天就卖出股票状态(状态三),即:dp[i][2] ,只有一个操作:
# 昨天一定是持有股票状态(状态一),今天卖出
# 即:dp[i][2] = dp[i - 1][0] + prices[i];
# 达到冷冻期状态(状态四),即:dp[i][3],只有一个操作:
# 昨天卖出了股票(状态三)
# dp[i][3] = dp[i - 1][2];
# dp数组如何初始化
# 确定遍历顺序: for i in range(1,len(nums))
个人错误:
思路:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
if n == 0:
return 0
dp = [[0] * 4 for _ in range(n)] # 创建动态规划数组,4个状态分别表示持有股票、不持有股票且处于冷冻期、不持有股票且不处于冷冻期、不持有股票且当天卖出后处于冷冻期
dp[0][0] = -prices[0] # 初始状态:第一天持有股票的最大利润为买入股票的价格
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], max(dp[i-1][3], dp[i-1][1]) - 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] # 当前不持有股票且当天卖出后处于冷冻期的最大利润等于前一天不持有股票且不处于冷冻期的最大利润
return max(dp[n-1][3], dp[n-1][1], dp[n-1][2]) # 返回最后一天不持有股票的最大利润