309.最佳买卖股票时机含冷冻期
思路:
1.确定dp数组以及下标的含义:dp[i][j]
,表示为:第 i
天第 j
种情况(0 <= j <= 2
)下,所获取的最大利润。
对于每一天结束时的状态总共有以下几种:
- 买入状态:
- 今日买入
- 之前买入,之后一直持有无操作
- 卖出状态:
- 今日买出,正处于冷冻期
- 昨天卖出,今天结束后度过了冷冻期
- 之前卖出,度过了冷冻期后无操作
在买入状态中,今日买入和之前买入的状态其实可以看做是股票的持有状态,可以将其合并为一种状态。
在卖出状态中,昨天卖出和之前卖出的状态其实可以看做是无股票并度过了冷冻期状态,可以将其合并为一种状态。
这样总结下来可以划分为三个状态:
- 股票的持有状态。
- 无股票,并且处于冷冻期状态。
- 无股票,并且不处于冷冻期状态
2.确定状态转移公式:
- 第0种状态(股票的持有状态)下可以有两种状态推出,取最大的那一种赋值:
- 昨天就已经持有的:
dp[i][0] = dp[i - 1][0]
: - 今天刚买入的(则昨天不能持有股票也不能处于冷冻期,应来自于前天卖出状态):
dp[i][0] = dp[i - 1][2] - prices[i]
- 昨天就已经持有的:
- 第1种状态(无股票,并且处于冷冻期状态)下可以有一种状态推出:
- 今天卖出:
dp[i] = dp[i - 1][0] + prices[i]
- 今天卖出:
- 第2种状态(无股票,并且不处于冷冻期状态)下可以有两种状态推出,取最大的那一种赋值:
- 昨天卖出:
dp[i] = dp[i - 1][1]
- 之前卖出:
dp[i] = dp[i - 1][2]
- 昨天卖出:
3.初始化:
可以很明显看出第一天不做任何操作就是 dp[0][0] = 0
,第一次买入就是 dp[0][1] = -prices[i]
。
第一次卖出的话,可以视作为没有盈利(当天买卖,价格没有变化),即 dp[0][2] = 0
。第二次买入的话,就是 dp[0][3] = -prices[i]
。同理第二次卖出就是 dp[0][4] = 0
。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
size = len(prices)
if size == 0:
return 0
dp = [[0 for _ in range(4)] for _ in range(size)]
dp[0][0] = -prices[0]
for i in range(1, size):
dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i])
dp[i][1] = dp[i - 1][0] + prices[i]
dp[i][2] = max(dp[i - 1][1], dp[i - 1][2])
return max(dp[size - 1][0], dp[size - 1][1], dp[size - 1][2])
714.买卖股票的最佳时机含手续费
本题和动态规划:122.买卖股票的最佳时机II (opens new window)的区别就是这里需要多一个减去手续费的操作。
class Solution:
def maxProfit(self, prices: List[int], fee: int) -> int:
n = len(prices)
dp = [[0] * 2 for _ in range(n)]
dp[0][0] = -prices[0] #持股票
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee)
return max(dp[-1][0], dp[-1][1])