第一题就是让你在一个直方图里面求一个面积最大的矩阵,觉得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;
}
};