leetcode 11,84,85,三道典型求解面积的题

11.Container With Most Water

题目描述:

Given n non-negative integers a1a2, ..., an , where each represents a point at coordinate (iai). n vertical lines are drawn such that the two endpoints of line i is at (iai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You may not slant the container and n is at least 2.

 

The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.

思考:

如果在起点和终点之间,有比它们二者高的点,那可能面积会更大。

面积取决于起点和终点中较低的那个。

解决方案:

从开始和结束设置两个指针,哪一边比较低就将其对应的指针往中间的方向移一步。如果找到一个点的高度比它高的,就尝试将其替换,求解一下矩形面积,看是否更大。这道题比后面两道简单。

class Solution {
public:
    int maxArea(vector<int>& height) {
        int len=height.size();
        int i=0;
        int j=len-1;
        int area=0;
        int area_max=0;
        while(i<j)
        {
            area=(j-i)*min(height[i],height[j]);
            area_max=max(area,area_max);
            if(height[i]<=height[j])
            {
                i++;
            }
            else j--;
        }
        return area_max;
    }
};

84 Largest Rectangle in Histogram

题目描述:

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.


Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

这道题和11有很大不同,11的面积只取决于起点和终点,而84则要求在起点终点的面积还与它们中间高度最低的点有关(如果存在比二者的高度还低的点)。

常规做法,对于每个点来说,令该点高度为矩形面积的高,如果找到其左边界点i和右边界点j就可以求出矩形面积的宽度为j-i-1(边界点就是比它高度还低的点)。在所有的矩形面积中取最大值即可。但是这样的算法复杂度太高了,o(n^2)。

当a[i+1]>a[i]时,i是i+1的左边界点。

当a[i+1]<a[i]时,i+1是i的右边界点。

可以借助一个栈去存储左边界点的信息,然后从左到右去寻找右边界点。算法的关键就在这个栈上。

当a[i]>a[stack.top()]时,i入栈。栈是一个递增栈。stack.top()就是a[i]的左边界点。

当a[i]<a[stack.top()]时,找到了stack.top()的右边界点,将栈里的值弹出来,stack.top()得到左边界点。然后再依次将a[stack.top()]与a[i]进行比较。将以i为右边界的点全部弹出,求矩形面积。

stack.push(i)

两种特殊情况:

(1)找不到左边界:i点前面所有点的高度均大于等于i的高度,此时左边界索引为-1.对应到算法里为:当栈被弹空的情形。

(2)找不到右边界:循环到最后一个点,栈不为空说明有一些点的右边界还未找到,则它们的右边界索引为len。

我的疑惑:找到右边界的点被弹出,会不会影响后续点对左边界的搜索。弹出的点的高度值均比a[i]大,所以左边界不可能是这些被弹出的点,早就被i点先拦截了。左边界的栈是一个递增栈。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int len=heights.size();
        int h;
        int max_area=0;
        stack<int> s;
        for(int i=0;i<len;i++)
        {
            if(s.empty())
                s.push(i);
            while(!s.empty()&&heights[i]<heights[s.top()])
            {
                h=s.top();
                s.pop();
                if(s.empty())
                {
                     max_area=max(max_area,heights[h]*(i));
                }
                else
                {
                     max_area=max(max_area,heights[h]*(i-1-s.top()));
                }  
            }
            
            s.push(i);
            
        }
        while(!s.empty())
        {
            h=s.top();
            s.pop();
            if(s.empty())
            {
                max_area=max(max_area,heights[h]*(len));
            }
            else
            {
                max_area=max(max_area,heights[h]*(len-1-s.top()));
            }
        }
        return max_area;
    }
};

在leetcode上提交了好几次,一直不通过,所以调了一下bug.网上很多人的代码在第一个while循环的条件是:while(!s.empty()&&heights[i]<=heights[s.top()]),我觉得不应该加等号,因为高度相等的点不是它的边界点,边界点在计算矩形面积时不算在内,而相等点是会增加矩形面积的。

所以第一个while循环的条件应该是:while(!s.empty()&&heights[i]<heights[s.top()])

但是,我们会遇到很多特殊情况:[1,1,1],[2,4]

heights[i]=heights[s.top()],第一个数组的右边界应该为3才对,但是目前的算法会得出右边界为2.

第二个数组,只是把1放进栈里,然后就结束了循环,没有去寻找最后一个点的矩形面积。结果错失了最大值4

解决bug方法:在for循环外面,再去判断一下栈是否已经为空,不为空,说明右边界应该是len而不是len-1

85 Maximal Rectangle

题目描述:

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

Example:

Input:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
Output: 6

一开始我的思路就是用动态规划做,dp记录每个点水平方向和竖直方向连续‘1’的个数。但是后来我意识到这个和矩形面积不是一个概念。比如看例子的前三行和前三列,(2,2)点的连续1个数在水平和竖直方向都是3,但是矩形的最大面积却是3。

后来才知道先做84题,85题就很容易解了。我们从行入手,第一行的直方图就是[1,0,1,0,0],之后的每一行要将前面行的列连续考虑在内,也就相当于84题直方图的高度。因此,第二行就是[2,0,2,1,1],依次类推。每行都可以得到一个直方图,也就有一个直方图最大面积,选择其中最大者即可。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值