第一题就是让你在一个直方图里面求一个面积最大的矩阵,觉得O(n*n)的方法应该是非常显然了,枚举一个长方形,分别往前往后找到它的界,也就是第一个比这个长方形高度小的位置,然后两个界之差乘以这个长方形的高度就是结果,然后枚举所有长方形求最大值即可。这样的复杂度应该是过不了的,这题枚举长方形确实已经不能再优化了,但是找界的方法,可以用一个叫单调队列的东西在O(1)的时间找到。
我曾经做过这么一道题,一队小朋友排队,要你求每个小朋友往后看,最远能看到哪个位置的小朋友,也就是往后看第一个比自己高的人的位置。这个问题其实可以维护一个单调下降的队列(也可以理解为栈)来实现,具体的做法大概是:首先将第一个人入栈,接下来每次入栈的人如果看到栈顶元素比他矮,就顶掉栈顶元素,然后接着看能不能顶掉栈顶下面这个元素,直到栈顶元素比它大,或者栈空了。
举一个例子,
3 1 4 2 5
每次栈的顺序是
3
3 1
4
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; } };