柱状图中的最大矩阵面积
有一类题目,输入往往是一维数组,求解最值。表面看是一个普通的优化问题,直接想到用动态规划求解。但是在寻找最优子结构的时候,我们发现这个优化问题的最优子结构并不是那么清晰。这个时候我们可以看看这个问题可否转化为计算每个位置的短板。一旦能转化为短板问题,问题往往就能在 o(n) 时间解决。
题目
给定一个一维数组,描述一个柱状图中各个柱子的高度。矩阵宽度由数组下标衡量。求柱状图中能由柱子完全填充的最大矩形面积。
解析
短板:当前柱子的高度。因为当前柱子的高度决定了矩形面积的大小。
所以只要计算出每个位置以当前柱高height.at(i)为矩形长度的矩形面积,并更新最大面积即可。
如何计算每个位置以当前柱高为矩形长度的矩形的宽度呢?只需要从左到右扫描一遍,找到左边距离当前位置最近且高度刚好小于当前柱高的位置lmin.at(i);从右到左扫描一遍,找到右边距离当前位置最近且高度刚好小于当前柱高的位置rmin.at(i)。则当前矩形面积为
height.at(i)∗(rmin.at(i)−lmin.at(i)−1)
代码
int largestRectangleArea(vector<int>& height) {
int len = height.size();
vector<int> lmin(len+1, -1);
vector<int> rmin(len+1, len);
for(int i=1; i<len; i++)
{
if( height.at(i) > height.at(i-1) ) lmin.at(i) = i-1;
else
{
int j = i-1;
while( j>=0 && height.at(j) >= height.at(i) ) j = lmin.at(j);
lmin.at(i) = j;
}
}
for(int i=len-2; i>=0; i--)
{
if( height.at(i) > height.at(i+1) ) rmin.at(i) = i+1;
else
{
int j = i+1;
while( j<=len-1 && height.at(j) >= height.at(i) ) j = rmin.at(j);
rmin.at(i) = j;
}
}
int ret = 0;
for(int i=0; i<len; i++)
ret = max(ret, height.at(i) * (rmin.at(i) - lmin.at(i) - 1) );
return ret;
}
复杂度分析
该问题时间复杂度 o(n) ,空间复杂度 o(1) 。
二值矩阵中找元素全为1的面积最大矩阵
这道题可以调用上一道题的代码。关键在于如何转换。
问题分析
0 0 0 1
1 0 1 1
1 1 1 1
1 1 1 1
先看最简单的情况。假如输入矩阵如上。直观上看,最优值应该是4*2=8。从上往下一行一行地看。在只有第一行时,最优值为1;前两行时,我们应该在两行的最优值中选最优值(最大值),也就是2。第二行的最优值计算时,我们会从上往下累计当前列连续的1的个数h,然后左右延伸,看以当前h为长的最大矩形。这个时候,我们发现对于每一行,我们只需要将h向量计算好,作为“柱状图中最大矩阵面积”的输入,求得最大值。然后更新全局最大值即可。
代码
int maximalRectangle(vector<vector<char>>& matrix) {
int m = matrix.size();
if(m==0) return 0;
int n = matrix.at(0).size();
vector< vector<int> > buf( m, vector<int>(n, 0) );
int ret = 0;
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
if(i==0) buf.at(i).at(j) = matrix.at(i).at(j) - '0';
else buf.at(i).at(j) = (matrix.at(i).at(j)=='1') ? (buf.at(i-1).at(j)+1) : 0;
}
ret = max(ret, largestRectangleArea(buf.at(i)) );
}
return ret;
}
复杂度分析
该问题时间复杂度 o(n2) ,空间复杂度 o(n2) 。