買賣股票最佳時機(I II III IV 冷凍期,手續費)
阿新 • • 發佈:2019-01-04
共6個問題:
分析:
- 只允許一次交易的最大收益(一次買進賣出)動態規劃: dp[i] = max(dp[i-1], prices[i] - minval);
- 允許多次交易的最大收益(多次買進賣出)貪心演算法:只要盈利就交易;
- 只允許有兩次交易的最大收益(兩次買進賣出)動態規劃:
1) dp1[i] = max(dp[i-1], prices[i] - minval) 從前往後遍歷,表示第1天到第i天之間的最大利潤(通過是否在第i天賣出確認);
2) dp2[i] = max(dp[i+1], maxval - prices[i]) 從後往前遍歷,表示第i天到最後一天之間的最大利潤(通過是否在第i天買進確認);
3) res = max(dp1 + dp2),(dp1 + dp2)[i] 正好表示從第1天到最後一天經過兩次交易的最大利潤,我們的目標是知道令總利潤最大的i。 - 只允許k次交易的最大收益(k次買進賣出)動態規劃:
local[i][j]表示第i天進行了j筆交易,且第j筆是在第i天完成的的最大收益;
global[i][j]表示第i天進行了j筆交易的最大收益,是目前為止全域性最優,不規定第j筆在哪天完成。則遞推公式為:
1) local[i][j] = max(global[i-1][j-1]+max(0, prices[i]-prices[i-1]), local[i-1][j]+prices[i]-prices[i-1])
2) global[i][j] = max(local[i][j], global[i-1][j])
3) 雙重迴圈,計算最後取global[-1][-1]
4) 注意當k大於天數時,直接用貪心演算法。 - 有冷凍期的最大交易(一次買賣後需要冷凍一天)動態規劃:
sell[i]表示截至第i天,最後一個操作是賣時的最大收益;
buy[i]表示截至第i天,最後一個操作是買時的最大收益;
cool[i]表示截至第i天,最後一個操作是冷凍期時的最大收益;
遞推公式:
sell[i] = max(buy[i-1]+prices[i], sell[i-1]) (第一項表示第i天賣出,第二項表示第i天冷凍)
buy[i] = max(cool[i-1]-prices[i], buy[i-1]) (第一項表示第i天買進,第二項表示第i天冷凍)
cool[i] = max(sell[i-1], buy[i-1], cool[i-1]) - 有手續費的最大交易(每買賣一次都會扣除一次手續費) 動態規劃
dp1[i]表示第i天手上有股票,dp2[i]表示第i天手上沒有股票,遞迴方程:
1) dp1[i] = max(dp1[i-1], dp2[i-1] - prices[i]) (第二項表示在第i天買入股票)
2) dp2[i] = max(dp2[i-1], dp1[i-1] + prices[i] - fee) (第二項表示在第i天將股票賣出,需扣除手續費)
程式碼:
#買賣股票最佳時機I(只允許一次交易)
class Solution(object):
def maxProfit(self, prices):
n = len(prices)
if n == 0:
return 0
dp = [0 for _ in range(n)]
minval = prices[0]
for i in range(1, n):
dp[i] = max(dp[i-1], prices[i] - minval)
minval = min(minval, prices[i])
return dp[-1]
#買賣股票最佳時機II(允許多次交易)
class Solution:
def maxProfit(self, prices):
#貪心演算法,只要出現盈利情況,就算作一次交易
n = len(prices)
if n == 0:
return 0
res = 0
for i in range(1,n):
res += max(0, prices[i]-prices[i-1])
return res
#買賣股票最佳時機III(只允許兩次交易)
class Solution:
def maxProfit(self, prices):
n = len(prices)
if n < 2:
return 0
dp1 = [0 for _ in range(n)]
dp2 = [0 for _ in range(n)]
minval = prices[0]
maxval = prices[-1]
#前向
for i in range(1,n):
dp1[i] = max(dp1[i-1], prices[i] - minval)
minval = min(minval, prices[i])
#後向
for i in range(n-2,-1,-1):
dp2[i] = max(dp2[i+1], maxval - prices[i])
maxval = max(maxval, prices[i])
dp = [dp1[i] + dp2[i] for i in range(n)]
return max(dp)
#買賣股票最佳時機IV(只允許k次交易)
class Solution:
def maxProfit(self, k, prices):
if k <= 0 or len(prices) == 0:
return 0
if k > len(prices):
return self.greedy(prices)
l = [[0 for _ in range(k+1)] for _ in range(len(prices))]
g = [[0 for _ in range(k+1)] for _ in range(len(prices))]
for i in range(1,len(prices)):
diff = prices[i] - prices[i-1]
for j in range(1,k+1):
l[i][j] = max(g[i-1][j-1] + max(0, diff), l[i-1][j] + diff)
g[i][j] = max(l[i][j], g[i-1][j])
return g[-1][-1]
def greedy(self, prices):
res = 0
for i in range(1,len(prices)):
res += max(0, prices[i]-prices[i-1])
return res
#買賣股票最佳時機(含冷凍期)
class Solution:
def maxProfit(self, prices):
n = len(prices)
if n == 0:
return 0
sell = [0 for _ in range(n)]
buy = [0 for _ in range(n)]
cool = [0 for _ in range(n)]
buy[0] = -prices[0]
for i in range(1,n):
sell[i] = max(buy[i-1] + prices[i], sell[i-1])
buy[i] = max(cool[i-1] - prices[i], buy[i-1])
cool[i] = max(sell[i-1], buy[i-1],cool[i-1])
return sell[-1]
#買賣股票最佳時機(含手續費)
class Solution:
def maxProfit(self, prices, fee):
n = len(prices)
if n < 2:
return 0
dp1 = [0 for _ in range(n)]#第i天手上有股票時的最大收益
dp2 = [0 for _ in range(n)]#第i天手上無股票時的最大收益
dp1[0] = -prices[0]
for i in range(1,n):
dp1[i] = max(dp1[i-1], dp2[i-1] - prices[i])
dp2[i] = max(dp2[i-1], dp1[i-1] + prices[i] - fee)
return dp2[n-1]