了解简洁的DP解决方案,以最佳时间买卖股票IV

时间:2020-07-31 02:45:34

标签: algorithm dynamic-programming

问题出在著名的leetcode problem(或在其他类似情况下),最好以最多k笔交易买卖股票。 这是问题的屏幕截图:

enter image description here

我正在尝试理解这种DP解决方案。您可以忽略大k的第一部分。我不了解dp部分的工作原理。

class Solution(object):
    def maxProfit(self, k, prices):
        """
        :type k: int
        :type prices: List[int]
        :rtype: int
        """
        # for large k greedy approach (ignore this part for large k)
        if k >= len(prices) / 2:
            profit = 0
            for i in range(1, len(prices)):
                profit += max(0, prices[i] - prices[i-1])
            return profit

#       Don't understand this part 
        dp = [[0]*2 for i in range(k+1)]
                             
        for i in reversed(range(len(prices))):
            for j in range (1, k+1):
                dp[j][True] = max(dp[j][True], -prices[i]+dp[j][False])
                dp[j][False] = max(dp[j][False], prices[i]+dp[j-1][True])
            
        return dp[k][True]        

我能够驱动类似的解决方案,但是它使用两行(dp和dp2)而不是仅一行(以上解决方案中的dp)。对我来说,解决方案似乎是覆盖自身的值,对于这种解决方案来说,这看起来不合适。但是答案有效并通过了leetcode。

1 个答案:

答案 0 :(得分:2)

让我们说几句话:

for i in reversed(range(len(prices))):

在考虑以后的价格之后,我们已经预先知道了每个未来价格。

  for j in range (1, k+1):

对于将这个价格视为k两次价格交易之一的每种可能性。

    dp[j][True] = max(dp[j][True], -prices[i]+dp[j][False])

如果我们认为这可能是一次购买-由于我们在时间上会倒退,那么购买就意味着已完成交易-我们在考虑{{1 }}次购买(j)或(2)减去此价格作为购买并添加我们已经获得的最佳结果,其中包括第dp[j][True]次销售(j)。

-prices[i] + dp[j][False]

否则,我们可能会将其视为一笔交易(由于我们往后退,因此是交易的前半部分),因此我们选择(1)已考虑的第 dp[j][False] = max(dp[j][False], prices[i]+dp[j-1][True]) 次交易中的最佳交易({{1 }}),或者(2)我们将此价格作为销售价格,并加上到目前为止,我们对第一批j完成的交易(dp[j][False])的最佳结果。

请注意,第一个(j - 1)是指第prices[i] + dp[j-1][True]个“半交易”,如果您愿意的话,因为我们会倒退,所以这笔交易会在以更高的价格迭代。然后,我们可以考虑将这个价格作为第dp[j][False]次销售来覆盖它。