找到最大可能区域

时间:2012-05-20 02:21:05

标签: algorithm area

  

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

     

注意:您可能不会倾斜容器。

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

另一个解决方案可能是使用DP来查找每个索引的最大区域,然后在索引n处,我们将获得最大区域。 我认为这是O(n)。

可以有更好的解决方案吗?

7 个答案:

答案 0 :(得分:3)

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;
}

答案 1 :(得分:2)

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

<强>解决方案

  1. 删除所有元素aj,使ai&gt; = aj =&lt; ak和i&gt; j&lt; ķ。这可以在线性时间内完成。
    1. 找到最大值am
    2. 设as = a1
    3. 对于j = 2到m-1,如果为&gt; = aj,则删除aj,否则为= aj
    4. 设as = a
    5. 对于j = n-1到m + 1,如果为&gt; = aj,则删除aj,否则为= aj
  2. 请注意,结果值看起来像金字塔,也就是说,最大值左边的所有元素都严格增加,右边的元素严格减少。
  3. i = 1,j = n。 m是最大的位置
  4. 虽然i&lt; = m且j&gt; = m
    1. 查找ai和aj之间的区域并跟踪最大值
    2. 如果ai&lt; aj,i + = 1,否则j- = 1
  5. 复杂性是线性的(O(n))

答案 2 :(得分:1)

这是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;
}

答案 3 :(得分:1)

这是一个干净的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

答案 4 :(得分:0)

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

  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. 尽可能高地开始你的水位,这是两个列表前面墙壁高度的最小值。使用这些墙计算水的总体积(可能是负的或零,但没关系),然后通过从其中一个列表中弹出一个元素来降低水位,使水位下降最少。计算每个高度的可能水量并取最大值

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

    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全部以线性时间运行,因此完整的解决方案也需要线性时间。

答案 5 :(得分:0)

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

我在this blog找到了一个非常明确的解释。不久,它如下:

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

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

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

  3. 因此,如果身高[左]&lt;左,则向左更改为(左+ 1)高度[右],否则向右改为(右-1)。

  4. 计算新区域,如果它比目前为止更好,则替换。

  5. 如果留下&lt;对,从2开始。

  6. 我在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]);
    }
    

答案 6 :(得分:-1)

此问题是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