开始漫长的补卡计划,这次是买卖股票系列的最后一天。88. 买卖股票的最佳时机 IV,309. 买卖股票的最佳时机含冷冻期,714. 买卖股票的最佳时机含手续费。分别对应K次买卖,包含冷冻期的买卖和包含手续费的买卖。包含手续费的买卖比较简单,直接把它当作股票价格涨了相应的费用就行。
188. 买卖股票的最佳时机 IV - 力扣(LeetCode)
买卖股票Ⅲ的升级版,最多K次买卖,Ⅲ相当于K=2 。但是还是比较简单的,因为整体思路变化不大,只需要多添加一维变量去监测K的奇偶变化就行(奇偶主要反映的是持有和未持有两种状态)。
首先是创建DP数组,行数为2k+1,就是每一次买卖都有第n次持有和第n次未持有的状态加上最初的初始状态。然后初始化也和之前一样,对每个奇数次初始为股票消费。然后遍历就是记住j从0出发,+1代表了持有的状态,+2代表了未持有的状态,然后依次循环就可以。感觉简单主要是思路上和之前没有太大变化,也就是题目中的状态没有多少变化。
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
if len(prices) == 0:
return 0
n = len(prices)
dp = [[0] * (2*k+1) for _ in range(n)]
for j in range(1, 2*k, 2):
dp[0][j] = -prices[0]
for i in range(1, len(prices)):
for j in range(0, 2*k-1,2):
dp[i][j+1] = max(dp[i-1][j+1], dp[i-1][j]-prices[i])
dp[i][j+2] = max(dp[i-1][j+2], dp[i-1][j+1]+prices[i])
return dp[-1][k*2]
309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode)
属于是Ⅱ的改版,在卖股票后加了一天冷冻期,但是本身是可以进行无限次买卖。感觉难得原因就是状态变化太快了,自己做的时候也尝试了更新一下状态,变为4种,分别是是否持有股票,是否进入冷静期,但是做起来的时候发现还有问题。
看了题解发现也是四种状态,但是定义有所不同,持有0,未持有1,今天卖出2,在冷冻期3。递推公式复制全一点,比较好理解。(有2和3的主要原因是要准确表明股票卖出的时间以及冷冻期开始的时间)
达到买入股票状态(状态一)即:dp[i][0],有两个具体操作:
那么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];
最后一个注意的点是在最后return的时候,要在三种状态中取最大值,因为其实这三种状态都算在未持有的里面。感觉还是难在怎么想这些状态上了,然后就是需要想好怎么去做状态之间的转移。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
if n <= 1:
return 0
dp = [[0]*4 for _ in range(n)]
# 持有0 未持有1 卖出股票2 在冷冻期3
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][2], dp[n-1][3], dp[n-1][1])