LeetCode:123. 买卖股票的最佳时机 III—————困难!(动态规划。。。)

题目
123. 买卖股票的最佳时机 III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
     随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:
输入:prices = [7,6,4,3,1] 
输出:0 
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

示例 4:
输入:prices = [1]
输出:0
 
 
提示:
1 <= prices.length <= 105
0 <= prices[i] <= 105

解题思路1

  • 动态规划。
  • 状态定义——当天可获得最大利润=dp[天数][完成的交易笔数][是否持有股票]
  • 因为我们有三种选择,买股票、卖股票和什么也不操作,当我们没有股票的时候可以买股票,当我们有股票的时候必须卖股票。所以我们这里规定:0表示手里没有股票,1表示手里有股票。
  • 状态转移分析:如果我们今天手里没有股票,有两种情况,一种是我们昨天手里也没有股票且今天不买股票,另一种是昨天手里有股票且今天把股票卖出去了。。。。如果我们今天手里有股票,有两种情况,一种是昨天手里有股票且今天不卖股票,另一种就是昨天没有股票且今天买入股票。
  • 状态转移————dp[i][j][0]=max(dp[i−1][j][0],dp[i−1][j−1][1]+prices[i])dp[i][j][1]=max(dp[i−1][j][1],dp[i−1][ j ][0]−prices[i])
  • 状态初始化————dp[i][0][0]:第 i 天没有完成交易,手里也没有股票,最大利润只能是0,因为我们什么都没有做。
  • 状态初始化————dp[0][0][1]:第 i 天没有完成交易,手里有股票,最大利润只能是 -prices[0],因为我们只能持有第0天的股票。
  • 状态初始化————我们可以初始化数组的时候把所有值都设成负无穷,再根据前两个状态初始化给一些特殊点赋值。
  • 最后一步————根据我们设定的状态和题目要求,最终的答案是最后一天所有可能完成的交易笔数里面利润最大的,也就是 max(dp[n-1][0...2][0])

Code1

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n == 1:
            return 0  
        dp = [[[float('-inf')] * 2 for h in range(3)] for h in range(2)]   #负无穷 float("-inf")   后面的是防止数组越界    
        # 初始条件
        for i in range(2):
            dp[i][0][0] = 0    
        dp[0][0][1] = -prices[0]
        
        for i in range(1,n):
            # 当k为0的时候,第一个方程不适用,因为会出现-1
            dp[i%2][0][1] = max(dp[(i-1)%2][0][1],-prices[i])
            for k in range(1,3):
                dp[i%2][k][0] = max(dp[(i-1)%2][k][0],dp[(i-1)%2][k-1][1]+prices[i])
                dp[i%2][k][1] = max(dp[(i-1)%2][k][1],dp[(i-1)%2][k][0]  -prices[i])
        
        # 确定答案
        res = 0
        for i in range(3):
            res = max(res,dp[(n-1)%2][i][0])
        return res

运行结果
LeetCode:123. 买卖股票的最佳时机 III—————困难!(动态规划。。。)_第1张图片
解题思路2
由于我们最多可以完成两笔交易,因此在任意一天结束之后,我们会处于以下五个状态中的一种:

  • 未进行过任何操作
  • 只进行过一次买操作
  • 进行了一次买操作和一次卖操作,即完成了一笔交易
  • 在完成了一笔交易的前提下,进行了第二次买操作
  • 完成了全部两笔交易

由于第一个状态的利润显然为 0,因此我们可以不用将其记录。对于剩下的四个状态,我们分别将它们的最大利润记为buy1,sell1,buy2以及sell2.

Code(优化后的结果)

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        buy1 = buy2 = -prices[0]
        sell1 = sell2 = 0
        for i in range(1, n):
            buy1 = max(buy1, -prices[i])
            sell1 = max(sell1, buy1 + prices[i])
            buy2 = max(buy2, sell1 - prices[i])
            sell2 = max(sell2, buy2 + prices[i])
        return sell2

运行结果
LeetCode:123. 买卖股票的最佳时机 III—————困难!(动态规划。。。)_第2张图片

你可能感兴趣的:(Leetcode算法刷题,动态规划,算法,leetcode,数据结构)