1. 程式人生 > >買賣股票最佳時機(I II III IV 冷凍期,手續費)

買賣股票最佳時機(I II III IV 冷凍期,手續費)

共6個問題:

買賣股票最佳時機

買賣股票最佳時機 II

買賣股票最佳時機 III

買賣股票最佳時機 IV

最佳買賣股票時機含冷凍期

買賣股票最佳時機含手續費

分析:

  1. 只允許一次交易的最大收益(一次買進賣出)動態規劃: dp[i] = max(dp[i-1], prices[i] - minval);
  2. 允許多次交易的最大收益(多次買進賣出)貪心演算法:只要盈利就交易;
  3. 只允許有兩次交易的最大收益(兩次買進賣出)動態規劃
    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。
  4. 只允許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大於天數時,直接用貪心演算法。
    https://blog.csdn.net/linhuanmars/article/details/23236995
  5. 有冷凍期的最大交易(一次買賣後需要冷凍一天)動態規劃
    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])
    https://www.cnblogs.com/grandyang/p/4997417.html
  6. 有手續費的最大交易(每買賣一次都會扣除一次手續費) 動態規劃
    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]