【问题标题】:Trapping rain water: Bug in brute force approach捕获雨水:蛮力方法中的错误
【发布时间】:2018-11-21 05:54:45
【问题描述】:

我一直在研究 Leetcode 上 problem 的不同算法,以 approach 1 开头。如果数组值为墙壁的高度,则该问题需要计算总水域面积(列宽 = 1)。

第一种方法是找到每根柱子左右两侧最大墙高中的最小高度,如果柱高小于最小值,则在给定柱子的顶部加水。取最小值,因为这是收集的水可以达到的最高值。要计算每一边的最大值,需要对左右进行n-1 遍历。

我用 Python 编写代码,但这里是 C++ 代码,按照Leetcode 上给出的解决方案。

int trap(vector<int>& height)
{
    int ans = 0;
    int size = height.size();
    for (int i = 1; i < size - 1; i++) {
        int max_left = 0, max_right = 0;
        for (int j = i; j >= 0; j--) { //Search the left part for max bar size
            max_left = max(max_left, height[j]);
        }
        for (int j = i; j < size; j++) { //Search the right part for max bar size
            max_right = max(max_right, height[j]);
        }
        ans += min(max_left, max_right) - height[i];
    }
    return ans;
}

我注意到左右列的最大值包括外循环迭代中的当前列。这样可以得到的最小值是0。请确认这是正确的。我在0potentialWater 之间使用了min(),以收集到我的代码中。

我查看了代码并以自己的方式重写了它,但我得到了0,因为我收集的雨水总量应该得到6。我的代码中的错误在哪里?

class Solution:
  def trap(self, height):
    """
    :type height: List[int]
    :rtype: int
    """

    if len(height) <= 2:
      return 0

    water = 0
    for col in range(1, len(height)-1):
      maxLeft = 0
      maxRight = 0

      for index in range(col):
        maxLeft = max(maxLeft, height[index])
      for index in range(col+1,len(height)):
        maxRight = max(maxRight, height[index])

      minHeight = min(maxLeft, maxRight)
      # print(col, minHeight)
      # minHeight = min(max(height[:col]), max(height[col+1:]))
      potentialWater = minHeight - col
      # print(potentialWater)
      # water += potentialWater
      water += max(0, potentialWater) # in case this is the highest column

    return water

solution = Solution()
height = [0,1,0,2,1,0,1,3,2,1,2,1]
print(solution.trap(height))

【问题讨论】:

  • 不知道这是否是您的问题,因为它是大量代码转储,但快速浏览一下,C++ 代码在内循环中包含 i,但您的 Python 代码是不包括等效内部循环中的col。你真的应该用惯用的 Python 重写这些东西(例如,maxRight = max(height[col:])),所以一开始就不会出现一个接一个的错误。 (顺便说一句,这在 C++ 中也是一个更好的答案……)但是,如果您真的想在与 C++ 代码相同的级别上做事,请确保您所做的完全相同。打印要比较的循环变量等。
  • @heretoinfinity 是的,这意味着复制列表的一半。但是对于许多现实生活中的问题,这并不重要——对于大多数性能很重要的现实生活中的问题,您应该使用 numpy 数组或类似的而不是列表(并且 numpy 数组在切片时返回就地视图) .如果您遇到 numpy 不适合但确实需要优化的一小部分问题,那么至少先让它工作,然后在工作后进行优化。
  • 另外,在优化之前,测量。当然,如果列表很大,复制会很痛苦,甚至可能会破坏您的代码。但是,如果我们只讨论几千个元素,考虑到切片内的优化循环和单个 max 调用与慢速通用 for循环并一遍又一遍地调用max
  • 假设工作实际上是在Python中(使用CPython):如果您不仅可以指出切片副本,还可以解释如何使用timeitsys.getsizeof来比较权衡,那么我会印象深刻的。 (但能够猜出你从这些比较中得到的答案,我什至不会真正问任何人,除非他们声称自己是低级 Python 专家或其他人。)

标签: python c++ arrays algorithm


【解决方案1】:

简单的调试策略很快将问题缩小到这一行:

  potentialWater = minHeight - col

为什么要从最小高度减去列number???这些根本不是同一类数量。相反,您想减去当前列的 高度

  potentialWater = minHeight - height[col]

有了这个改变,我们得到了想要的输出:

$ python3 trap.py
6

正如评论已经指出的那样,您应该为此使用 Pythonic 编程习惯,例如替换

for index in range(col):
  maxLeft = max(maxLeft, height[index])
for index in range(col+1,len(height)):
  maxRight = max(maxRight, height[index])

maxLeft = max(height[:col])
  maxRight = max(height[col+1:])

【讨论】:

  • 就像我在上面问过 abernett 一样,max(height[col:]) 不会使用额外的空间吗?我从列表切片开始,但当我意识到我可能会使用额外的空间时将其注释掉。
  • 在这里我得到了切片使用辅助内存的观点。请确认是否正确。 stackoverflow.com/questions/47128421/…
  • 你说的很对; abarnert 已经告诉了你我想说的一切,而且更深入一点。
  • 谢谢。有时人们不会在自己的 cmets 上回复 cmets,因此也是在这里发帖的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 2012-07-24
  • 2019-05-29
  • 1970-01-01
相关资源
最近更新 更多