LeetCode Largest Rectangle in Histogram&&Maximal Rectangle

来源:互联网 发布:php 高德地图api接口 编辑:程序博客网 时间:2024/06/08 07:46

第一题就是让你在一个直方图里面求一个面积最大的矩阵,觉得O(n*n)的方法应该是非常显然了,枚举一个长方形,分别往前往后找到它的界,也就是第一个比这个长方形高度小的位置,然后两个界之差乘以这个长方形的高度就是结果,然后枚举所有长方形求最大值即可。这样的复杂度应该是过不了的,这题枚举长方形确实已经不能再优化了,但是找界的方法,可以用一个叫单调队列的东西在O(1)的时间找到。

我曾经做过这么一道题,一队小朋友排队,要你求每个小朋友往后看,最远能看到哪个位置的小朋友,也就是往后看第一个比自己高的人的位置。这个问题其实可以维护一个单调下降的队列(也可以理解为栈)来实现,具体的做法大概是:首先将第一个人入栈,接下来每次入栈的人如果看到栈顶元素比他矮,就顶掉栈顶元素,然后接着看能不能顶掉栈顶下面这个元素,直到栈顶元素比它大,或者栈空了。

举一个例子,

3 1 4 2 5

每次栈的顺序是

3

3 1

4

2

当4进去的时候,把3,1都顶掉了,这说明3和1 的答案都是4,最后栈里面还有2个元素,说明他们后面没有比他们高的人。这个做法最多每个元素进栈一次,出栈一次,复杂度O(n)。

对于直方图这个题,我只要先花O(N)的时间将每一个长方形左侧和右侧第一个比它小的位置记录下来,然后再花O(n)时间枚举长方形时,只需要O(1)的时间就能获得界,即可得到答案。

代码如下:

int la[100201];int ra[100201];int st[100201][2];class Solution {public:    int largestRectangleArea(vector<int> &height) {        int i;        int n = height.size();        if (n == 0)            return 0;        for (i = 0; i<n; i++)        {            la[i] = -1;            ra[i] = n;        }        int top = 0;        st[top][0] = height[0];        st[top][1] = 0;        top++;        for (i = 1; i<n; i++)        {            while (height[i]<st[top - 1][0])            {                top--;                ra[st[top][1]]=i;                if (top == 0)                    break;            }            st[top][0] = height[i];            st[top][1] = i;            top++;        }        top = 0;        st[top][0] = height[n - 1];        st[top][1] = n - 1;        top++;        for (i = n - 2; i >= 0; i--)        {            while (height[i]<st[top - 1][0])            {                top--;                la[st[top][1]] = i;                if (top == 0)                    break;            }            st[top][0] = height[i];            st[top][1] = i;            top++;        }        int ans = 0;        for (i = 0; i < n; i++)        {            //cout << la[i] << " " << ra[i] << endl;            if (ans < (ra[i] - la[i] - 1)*height[i])                ans = (ra[i] - la[i] - 1)*height[i];        }        return ans;    }};

接下来这题最大全1矩阵,与直方图这题有着非常密切的关系,如果我把这个01矩阵的前面i行加一起(如果中间出现了0就断开了),那么它就是在一个直方图里面找最大的矩阵,所以现在这个问题就是变成了多个直方图的最大矩阵,之所以为多个,是因为,前i行算一个,总共有n个,需要注意的是要处理被0断开的情况。代码非常相似,如下:

class Solution {public:    int h[10001];    int la[100201];    int ra[100201];    int st[100201][2];    int maximalRectangle(vector<vector<char> > &matrix) {        int i,j;        int n,m;                n=matrix.size();        if(n==0)            return 0;        m=matrix[0].size();        memset(h,0,sizeof(h));        int ans=0;        for(i=0;i<n;i++)        {            for(j=0;j<m;j++)            {                if(matrix[i][j]=='1')                    h[j]++;                else                    h[j]=0;            }            for (j = 0; j<m ; j++)            {                la[j] = -1;                ra[j] = m;            }            int top = 0;            st[top][0] = h[0];            st[top][1] = 0;            top++;            for (j = 1; j<m; j++)            {                while (h[j]<st[top - 1][0])                {                    top--;                    ra[st[top][1]]=j;                    if (top == 0)                        break;                }                st[top][0] = h[j];                st[top][1] = j;                top++;            }            top = 0;            st[top][0] = h[m - 1];            st[top][1] = m - 1;            top++;            for (j = m - 2; j >= 0; j--)            {                while (h[j]<st[top - 1][0])                {                    top--;                    la[st[top][1]] = j;                    if (top == 0)                        break;                }                st[top][0] = h[j];                st[top][1] = j;                top++;            }            for(j=0;j<m;j++)                if(ans<h[j]*(ra[j]-la[j]-1))                    ans=h[j]*(ra[j]-la[j]-1);        }        return ans;    }};


0 0