【问题标题】:Find the maximum possible area找到最大可能的区域
【发布时间】:2012-05-27 01:42:23
【问题描述】:

给定 n 个非负整数 a1, a2, ..., an,其中每个代表一个 点坐标 (i, ai)。绘制 n 条垂直线,使得 线 i 的两个端点在 (i, ai) 和 (i, 0)。找到两条线, 它与 x 轴一起形成一个容器,使得容器 含有最多的水。

注意:您不能倾斜容器。

一种解决方案可能是我们采用每一行并找到每一行的区域。这需要 O(n^2)。没有时间效率。

另一种解决方案是使用 DP 找到每个索引的最大面积,然后在索引 n 处,我们将获得最大面积。 我认为是 O(n)。

有没有更好的解决方案?

【问题讨论】:

  • 您能详细说明您正在考虑的 DP。由于 i 和 ai 之间没有关系,我认为你必须考虑所有组合,因为对于两个点 i 和 j,面积将为 (i-j)*min(ai,aj)。我认为您无法将其最大化。
  • @J.F.Sebastian 不确定问题是否相同。举个简单的例子:100, x, 200。如果 x
  • @ElKamina:你是对的。我应该说这些问题只是相关的。

标签: algorithm area


【解决方案1】:
int maxArea(vector<int> &height) {
    int ret = 0;
    int left = 0, right = height.size() - 1;
    while (left < right) {
        ret = max(ret, (right - left) * min(height[left], height[right]));
        if (height[left] <= height[right])
            left++;
        else
            right--;
    }
    return ret;
}

【讨论】:

  • 一般来说,纯代码的答案往往不是那么好。为什么不解释答案?
【解决方案2】:

这里的很多人都把这个问题误认为是最大矩形问题,事实并非如此。

解决方案

  1. 删除所有元素 aj,使得 ai >= aj = j
  2. 找到最大值am
  3. 令 as = a1
  4. 对于 j = 2 到 m-1,如果 as >= aj,则删除 aj,否则 as = aj
  5. 让 as = an
  6. 对于 j = n-1 到 m+1,如果 as >= aj,则删除 aj,否则 as = aj
  • 请注意,结果值看起来像一个金字塔,即最大值左侧的所有元素都严格递增,右侧的所有元素严格递减。
  • i=1,j=n。 m 是最大值的位置。
  • 当 i=m
    1. 查找 ai 和 aj 之间的区域并跟踪最大值
    2. 如果 ai
  • 复杂度是线性的 (O(n))

    【讨论】:

    • 考虑 4 在 3、10 在 4、10 在 5、4 在 6。最大的两个是 10 在 4 和 5,第 10 卷。检查 4 在 3 到 10 在 5 - 第 8 卷- 没有得到改善。在 4 到 4 到 6 时检查 10 的音量 - 第 8 卷 - 没有改善,但在 3 到 4 到 6 时的 4 是第 12 卷 - 会更好但错过了。通常,您可能会错过一个较宽的低答案,因为里面是一个狭窄的高答案,将其一分为二。
    • @mcdowella 是的。那是真实的!我会尽快完善我的答案。但关键是忽略两边至少有一个较大数字的数字。
    • 不必要的复杂。
    【解决方案3】:

    这是一个使用 Java 的实现:

    基本思路是用前后两个指针,沿途计算面积。

    public int maxArea(int[] height) {
        int i = 0, j = height.length-1;
        int max = Integer.MIN_VALUE;
    
        while(i < j){
            int area = (j-i) * Math.min(height[i], height[j]);
            max = Math.max(max, area);
            if(height[i] < height[j]){
                i++;
            }else{
                j--;
            }
        }
    
        return max;
    }
    

    【讨论】:

      【解决方案4】:

      这是一个干净的 Python3 解决方案。此解决方案的运行时间为 O(n)。请务必记住,两条线之间形成的区域由较短线的高度和线之间的距离决定。

      def maxArea(height):
          """
          :type height: List[int]
          :rtype: int
          """
          left = 0
          right = len(height) - 1
          max_area = 0
          while (left < right):
              temp_area = ((right - left) * min(height[left], height[right]))
              if (temp_area > max_area):
                  max_area = temp_area
              elif (height[right] > height[left]):
                  left = left + 1
              else:
                  right = right - 1
          return max_area
      

      【讨论】:

        【解决方案5】:

        这个问题可以在线性时间内解决。

        1. 按照从高到低的顺序构造一个可能的左墙列表(位置+高度对)。这是通过获取最左边的可能墙并将其添加到列表中来完成的,然后从左到右遍历所有可能的墙,并获取所有大于添加到列表中的最后一堵墙的墙。例如对于数组

          2 5 4 7 3 6 2 1 3
          

          你可能的左墙是(对是 (pos, val)):

          (3, 7) (1, 5) (0, 2)
          
        2. 以相同的方式构造一个可能的右墙列表,但从右到左。对于上面的数组,可能的右墙是:

          (3, 7) (5, 6) (8, 3)
          
        3. 开始时水位尽可能高,即两个列表前面墙壁的最低高度。使用这些墙壁计算水的总体积(它可能是负数或零,但没关系),然后通过从其中一个列表中弹出一个元素来降低水位,以使水位下降最少。计算每个高度可能的水量并取最大值。

        在这些列表上运行此算法如下所示:

        L: (3, 7) (1, 5) (0, 2)  # if we pop this one then our water level drops to 5
        R: (3, 7) (5, 6) (8, 3)  # so we pop this one since it will only drop to 6
        Height = 7
        Volume = (3 - 3) * 7 = 0
        Max = 0
        
        L: (3, 7) (1, 5) (0, 2)  # we pop this one now so our water level drops to 5
        R: (5, 6) (8, 3)         # instead of 3, like if we popped this one
        Height = 6
        Volume = (5 - 3) * 6 = 12
        Max = 12
        
        L: (1, 5) (0, 2)
        R: (5, 6) (8, 3)
        Height = 5
        Volume = (5 - 1) * 5 = 20
        Max = 20
        
        
        L: (1, 5) (0, 2)
        R: (8, 3)
        Height = 3
        Volume = (8 - 1) * 3 = 21
        Max = 21
        
        L: (0, 2)
        R: (8, 3)
        Height = 2
        Volume = (8 - 0) * 2 = 16
        Max = 21
        

        步骤 1、2 和 3 都以线性时间运行,因此完整的解决方案也需要线性时间。

        【讨论】:

          【解决方案6】:

          The best answerBlack_Rider,但他们没有提供解释。

          我在this blog 上找到了非常清楚的解释。很快,它是这样的:

          给定长度为 n 的数组高度:

          1. 从尽可能宽的容器开始,即从左侧 0 到右侧 n-1。

          2. 如果存在更好的容器,它将更窄,因此它的两侧必须高于当前选择的低侧。

          3. 因此,如果 height[left]

          4. 计算新的面积,如果比你目前的好,替换。

          5. 如果左

          我在 C++ 中的实现:

          int maxArea(vector<int>& height) {
              auto current = make_pair(0, height.size() - 1);
              auto bestArea = area(height, current);
          
              while (current.first < current.second) {
                  current = height[current.first] < height[current.second]
                      ? make_pair(current.first + 1, current.second)
                      : make_pair(current.first, current.second - 1);
          
                  auto nextArea = area(height, current);
                  bestArea = max(bestArea, nextArea);
              }
          
              return bestArea;
          }
          
          inline int area(const vector<int>& height, const pair<int, int>& p) {
              return (p.second - p.first) * min(height[p.first], height[p.second]);
          }
          

          【讨论】:

            【解决方案7】:

            这个问题是The Maximal Rectangle Problem 的简单版本。给定的情况可以看作是一个二进制矩阵。将矩阵的行视为 X 轴,将列视为 Y 轴。对于数组中的每个元素 a[i],设置

            Matrix[i][0] = Matrix[i][1] = ..... = Matrix[i][a[i]] = 1
            

            例如 - 对于a[] = { 5, 3, 7, 1},我们的二进制矩阵由下式给出:

            1111100
            1110000
            1111111
            1000000
            

            【讨论】:

            • 你的表述是对的,但这不是最大矩形问题。如果选择 i,j,则体积为 min(ai,aj)*|i-j| .但是在最大矩形中,体积是 min(ai..aj)*|i-j| (假设 i
            猜你喜欢
            • 2019-02-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-20
            • 1970-01-01
            • 2019-10-23
            相关资源
            最近更新 更多