【问题标题】:understanding leetCode - 121. Best Time to Buy and Sell Stock - Ruby理解 leetCode - 121. 买卖股票的最佳时机 - 红宝石
【发布时间】:2021-10-06 19:12:47
【问题描述】:

我正在尝试了解我为以下 leetCode 问题找到的解决方案。

说明: “给定一组价格,其中价格 [i] 是给定股票在第 i 天的价格。 您希望通过选择一天购买一只股票并选择未来的另一天出售该股票来最大化您的利润。 返回您可以从此交易中获得的最大利润。如果无法获得任何利润,则返回 0。”

说明: “输入:价格 = [7,1,5,3,6,4] 输出:5 解释:第 2 天买入(价格 = 1),第 5 天卖出(价格 = 6),利润 = 6-1 = 5。 请注意,不允许在第 2 天买入在第 1 天卖出,因为您必须先买入再卖出。”

我遇到了这个我试图理解的解决方案。在“->”处分解它:

def max_profit([7,1,5,3,6,4])
  value = 0
  profit = 0

  (1...prices.size).each do |i|
    value += (prices[i] - prices[i-1])

-> 所以这里 value = 0 + (1-7 = -6)= -6 /value = -6 + (5-1=4)= -2 / value = -2+(3-5)= -4 以此类推以 -3 结尾

    value = [0, value].max

-> 这是我不明白的。现在 value = [0, value].max ,当我打印它时,我得到 0,4,2,5,3。

我看到这个的方式是: (在第一次迭代中)value = [0, -6].max,所以 value 为 0,因为 0 > 比 -6

但是当 value = [0, -2].max 时,我在第二次迭代中得到 4 ...不应该再次为 0 吗?怎么得到 0,4,2,5,3 ???

当我执行 value = [0, value].max 时实际发生了什么。 ?

profit = value if value > profit
  end

  profit
end

一百万谢谢

【问题讨论】:

    标签: ruby


    【解决方案1】:

    数组的#max 方法返回数组中的最大值,所以...[3, 7, 4].max 将返回7(最大值)

    value = [0, value].max 
    

    这基本上是返回较大的一个(零或value)并将其分配给value。因此它将value 中的任何负数替换为零,但如果它是正值则不理会它。

    做同样事情的另一种方法...

    value = 0 if value < 0
    

    【讨论】:

      【解决方案2】:

      注意条件you must buy before you sell,所以基本上我们找到了最大利润中的最大值(每个利润i是每个价格[i]和i之后的价格之间的差异的最大值)

      所以一个简单的解决方案是 2 个循环

      max of [
       max-profit-0: max of p[1] - p[0], p[2] - p[0], ...
       max-profit-1: max of p[2] - p[1], p[3] - p[2], ...
       ....
      ]
      

      但是您提供的解决方案非常棒,它只需要一个循环,利用以下几点:

      • 价格 0 和价格 2 之间的利润 == p[2] - p[0] == (p[1] - p[0]) + (p[2] - p[1])

        => 那就是代码value += (prices[i] - prices[i-1]) 做的事情,它将计算当前日期j(当前步骤)和开始日期i之间的利润 只要不同的仍然是积极的。

      • 如果上述总和在第 1 步和第 2 步是正数:p[1] - p[0] &gt; 0p[1] - p[0] + p[2] - p[1] &gt; 0,这意味着 p[0] &lt; p[1]p[0] &lt; p[2],我们可以得出结论,对于日期 2 之后的每个 p[j] (j > 2 ),p[j] - p[0] 总是大于p[j] - p[1]p[j] - p[2],所以我们可以继续计算总和(利润),起始索引为 0 并忽略 1 和 2,因为这个问题的目标是找到 MAX,对吧?

      代码value = [0, value].max将返回值,只要值是正数,然后值继续前进。

      • 如果上述总和(或利润)在第 1 步为正,在第 2 步为负:(p[1] - p[0]) + (p[2] - p[1]) &lt; 0 所以p[2] - p[0] &lt; 0p[1] - p[0] &gt; 0,这意味着p[2] &lt; p[0]p[0] &lt; p[1]

      • 所以我们有 p[2] &lt; p[0] &lt; p[1],显然对于日期 2 (j > 2) 之后的每个价格 p[j]p[j] - p[2] 总是大于 p[j] - p[0]p[j] - p[1],因此我们可以忽略 p[0]和 p[1],因为这个问题的目标是找到 MAX,对吧?

        这就是为什么我们可以将value 重置为零以再次开始计算利润 开始索引为 2,现在下一个循环中代码 value += (prices[i] - prices[i-1]) 的值实际上是 p[3] - p[2],而不是 p[3] - p[2] + p[2] - p[1]...,请记住我们已经缓存了范围 [0..2] 的最大利润。

        这是value = [0, value].max的代码,如果值

      [7, 1, 5, 3, 6, 4]
       +  - # that mean you sure that profits 
            # between each [5, 3, 6, 4] and [7] always < with [1]
            # so reset with date 1
      

      很好的解决方案!

      【讨论】:

        【解决方案3】:

        理解程序的一个好方法是简单地用笔和纸逐步完成它,同时跟踪所有(相关)状态。所以,让我们这样做吧。

        在我们的例子中,相关状态是两个局部变量profitvalue 以及迭代变量i 和扩展prices[i]prices[i-1] 的值。我们首先在方法的第 1 行和第 2 行将它们都初始化为值 0。然后,第 4-8 行是执行所有实际工作的循环;第 10 行简单地返回结果。很容易看出,第 5-7 行完成了所有工作,所以让我们关注那些:

        i line code what does it do? profit value prices[i] prices[i-1]
        1 5 value += (prices[i] - prices[i-1]) add the price difference to the current value 0 0 -6 = -6 7 1
        1 6 value = [0, value].max set value to the maximum of 0 and its current value, IOW set value to 0 if it is negative 0 0 7 1
        1 7 profit = value if value &gt; profit set profit to the maximum of its current value and value 0 0 7 1
        2 5 value += (prices[i] - prices[i-1]) add the price difference to the current value 0 0 + 4 = 4 1 5
        2 6 value = [0, value].max set value to the maximum of 0 and its current value, IOW set value to 0 if it is negative 0 4 1 5
        2 7 profit = value if value &gt; profit set profit to the maximum of its current value and value 4 4 1 5
        3 5 value += (prices[i] - prices[i-1]) add the price difference to the current value 4 4 - 2 = 2 5 3
        3 6 value = [0, value].max set value to the maximum of 0 and its current value, IOW set value to 0 if it is negative 4 2 5 3
        3 7 profit = value if value &gt; profit set profit to the maximum of its current value and value 4 4 5 3
        4 5 value += (prices[i] - prices[i-1]) add the price difference to the current value 4 2 + 3 = 5 3 6
        4 6 value = [0, value].max set value to the maximum of 0 and its current value, IOW set value to 0 if it is negative 4 5 3 6
        4 7 profit = value if value &gt; profit set profit to the maximum of its current value and value 5 5 3 6
        5 5 value += (prices[i] - prices[i-1]) add the price difference to the current value 5 5 - 2 = 3 6 4
        5 6 value = [0, value].max set value to the maximum of 0 and its current value, IOW set value to 0 if it is negative 5 3 6 4
        5 7 profit = value if value &gt; profit set profit to the maximum of its current value and value 5 3 6 4

        当我执行 value = [0, value].max 时实际发生了什么。 ?

        找出方法作用的最简单方法是阅读its documentation [注意,从技术上讲,此方法不是Enumerable#max,而是Array#max,但在此示例中它们的行为相同]:

        返回 enum 中具有最大值的对象。

        因此,换句话说,该方法正如其名称所暗示的那样:返回Enumerable 的最大值。

        请注意,这不是一种非常惯用的代码编写方式。例如,在第 6 行使用 max 和在第 7 行使用 if 做同样的事情是没有意义的:坚持一个或另一个,不要用两种不同的东西做同样的事情来混淆读者.此外,在 Ruby 中几乎从未手动迭代集合。使用Enumerable#each_cons 可以更好地表达这一点,例如Enumerable#max_byEnumerable#reduce。实际上,完美的解决方案是使用prefix sum aka scan,但不幸的是,Ruby 的核心库和标准库中没有。

        惯用的版本看起来更像这样:

        def max_profit(prices)
          prices.
            each_cons(2).
            reduce([0, 0]) do |(value, profit), (a, b)|
              [[temp = value + b - a, 0].max, [temp, profit].max] 
            do.
            last
        end
        

        或者这个:

        def max_profit(prices)
          prices.
            each_cons(2).
            map {|a, b| b - a }.
            reduce([]) do |res, difference|
              res << [(res[-1] || 0) + difference, 0].max
            end.
            max
        end
        

        【讨论】:

          猜你喜欢
          • 2020-05-06
          • 1970-01-01
          • 2021-06-07
          • 1970-01-01
          • 2020-10-04
          • 2018-03-20
          • 1970-01-01
          • 2021-11-29
          • 1970-01-01
          相关资源
          最近更新 更多