概述
動態規劃的一種典型題型:
一般的動態規劃都是
dp[n] = f(dp[x])
但是有一種題型的動態規劃的轉移方程是:
dp[n] = f(g[x])
g[x] = dp[x]
這種就是含狀態機的動態規劃問題
股票交易問題的通用解法:
-
定義動態數組:
dp[i][k][0] 代表當前天是第i天,已經交易k次,現在不持有股票的最大利潤
dp[i][k][1] 代表當前天是第i天,已經交易k次,現在持有股票的最大例如 -
初始化:
初始化的方向主要有兩個原則:沒有交易的時候利潤爲0,不可能事件的利潤爲 -inf
第0天,如果還沒持有股票,利潤爲0
第0天,已經持有股票,利潤爲-price[0] -
轉移方程
# 賣出不消耗次數 # 第i天,已經進行k次交易,並且不持有股票,我的值要不然就是前一天已經進行k次交易且不持有股票。要不就是前一天只進行k次交易並且持有股票,然後今天我把股票賣掉 dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]) # 買入消耗次數 # 第i天,已經進行k次交易,並且持有股票,我的值要不然就是前一天已經進行k次交易且持有股票。要不就是前一天只進行k-1次交易並且不持有股票,然後今天我把股票買回來 dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])
-
循環區間
for i in range(size): for k in range(max_K,0,-1): #k爲什是倒敘呢,不理解?[max_k,1] pass
-
返回結果
最後一天,交易了max_k次,並且不持有股票的利潤dp[-1][max_k][0]
題型:k爲有限次
k爲1次:121. 買賣股票的最佳時機
class Solution:
def maxProfit(self, prices) -> int:
max_K = 1
size = len(prices)
if size == 0:
return 0
# dp[i][k][j] i [0,size-1] k [0,max_K] j [0,1]
dp = [[[0, 1] for _ in range(max_K + 1)] for _ in range(size)]
for i in range(size):
for k in range(max_K,0,-1):
if i == 0: # 初始化
dp[i][k][0] = 0
dp[i][k][1] = -prices[i]
else:
dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])
return dp[size - 1][max_K][0]
k爲2次:123. 買賣股票的最佳時機 III
class Solution:
def maxProfit(semaxlf, prices: List[int]) -> int:
max_k = 2
size = len(prices)
dp = [[[0,0] for _ in range(max_k + 1)] for i in range(size)]
if size == 0:
return 0
for i in range(size):
for k in range(max_k, 0, -1):
if i == 0:
dp[i][k][0] = 0
dp[i][k][1] = -prices[i]
else:
dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])
return dp[size - 1][max_k][0]
k次交易:188. 買賣股票的最佳時機 IV
class Solution:
def maxProfit(self, max_k: int, prices: List[int]) -> int:
size = len(prices)
if size == 0:
return 0
dp = [[[0,0] for i in range(max_k + 1)] for i in range(size)]
for i in range(size):
for k in range(max_k, 0, -1):
if i == 0:
dp[i][k][0] = 0
dp[i][k][1] = -prices[i]
else:
dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])
return dp[-1][max_k][0]
題型:k爲無限次
當k爲無限次的時候,k就不再有參考意義,k將退化成二維
-
定義dp
dp[i][0]
# 代表第i天不持有股票
dp[i][1]
# 代表第i天持有股票 -
初始化
當i爲0時:
dp[i][0 = 0 dp[i][1] = -price[0]
-
轉移方程
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])
k爲無限次:122. 買賣股票的最佳時機 II
class Solution:
def maxProfit(self, prices: List[int]) -> int:
size = len(prices)
if size == 0:
return 0
dp = [[0,0] for _ in range(size)]
for i in range(size):
if i == 0:
dp[i][0] = 0
dp[i][1] = -prices[i]
else:
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])
return dp[-1][0]
k爲無限次帶手續費:714. 買賣股票的最佳時機含手續費
根據示例可知,只是賣出的時候收手續費
class Solution:
def maxProfit(self, prices,fee) -> int:
size = len(prices)
if size == 0:
return 0
dp = [[0,0] for _ in range(size)]
for i in range(size):
if i == 0:
dp[i][0] = 0
dp[i][1] = -prices[i]
else:
dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i]-fee) # 賣出的時候交手續費
dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i])
return dp[-1][0]
k爲無限次,帶冷凍期:309. 最佳買賣股票時機含冷凍期
class Solution:
def maxProfit(self, prices: List[int]) -> int:
size = len(prices)
if size == 0:
return 0
dp = [[0,0] for _ in range(size)]
for i in range(size):
if i == 0:
dp[i][0] = 0
dp[i][1] = -prices[i]
elif i == 1:
dp[i][0] = max(0, prices[i]-prices[i-1]) #如果第二天沒有股票,要不第一天就沒有,要不就是第一天買了,第二天賣出
dp[i][1] = max(-prices[i-1], -prices[i]) # 我在第二天擁有股票,要不就是第一天買入,要不是第二天買入
else:
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])
dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i])
return dp[size - 1][0]