题目描述
给你一个矩阵,这个矩阵的值不是0就是1,现在让你求出由1构成的矩阵,最大面积是多少?
分析
1 0 1 1
1 1 1 1
1 1 1 0
1 1 1 1
如上就是这个图,这个答案是6。但是怎么用函数求出呢?
思路是这样的我们,分俩步来求出它。第一步分割,第二步算出分割后的当前最大子矩阵,最终答案就是所有分割当中的最大值。
分割是个意思,以当前行为基底,统计往上1的个数。如果当前行有某个值为0,则该高度就是0,否则该位置的高度就是1的个数。举个列子,第一行为基底,height[1 , 0 , 1 , 1] ,到了第二行,height [2 ,1 , 0 , 2 ] ,到了第三行,height[3 , 2 , 1 ,0 ],那么第四行,height [ 4 , 3 ,2 ,1 ]。
第一次分割时,用height求出当前矩阵大小。0号位不能向左扩展和向右扩展,故以0号为底的面积为1。1号位,不能向左扩展/扩展,面积为0。2号位,不能向左扩展,可以向右扩展,大小为2。3号位可以向左不能向右,大小为2。以这个方法求出最终的最大值。(是否能扩展取决于,它旁边的高度是否高于它,如果高于它就是可以扩展的)
实现
我们用栈来实现上面的每个height的最大面积。
思路是这样的,如果栈为空把当前height的下标入栈,栈不空判断以下,如果当前栈顶元素pos处对应的height的值小于目标元素对应的值,把目标元素入栈,如果大于则进行处理。
处理是这样的,一直出栈,直到遇见一个小于目标元素的值。对于新栈顶下标记为k,出栈的下标记为j。公式是 (i-1-(k+1)+1)*height[j] –> (i-k-1)*height[j]。
公式讲解
我们看第一个图 ,可以看出k~i-1都在栈里面。现在i要入栈了,它比栈顶元素小,现在执行处理,一直pop到k,k在height中的值是小于i的,入栈。现在计算大小,以j为底,它能最右边扩展到i-1,最左边到k+1。
我们看第二个图,j和i是相邻的,K+1到J-1的元素都大于j。首先绝不对不会小于K,也绝对不会小于j,因为小于K的话在栈中K和J不可能相邻。
其次为什么会在栈中J和K相邻但是在height中不相邻呢?是这样的,栈中俩个元素相邻,必定存在这样关系,J比k大。其次能相邻,一定是这俩种情况导致的,第一种本来j和k就相邻,第二种,相邻是由出栈处理导致。所以就出现了图2这种场景。那么我们算下现在的大小,左边界k+1,右边界i-1。底右边界减去左边界+1,面积底乘以高算出。
第三个图大家可以自己分析一下。
代码
/*这个问题需注意两点
向右最多扩展到i-1
向左最大扩展到i+1
因为 [k+1,i-1]这个序列的值都是大于height[j]的
因为你想以下如果它们之间还有下标值,那么j与k在栈中不可能相邻,相邻说明俩种情况
1. 是它们是原本就相邻的
2. 它们不相邻,但是它们之间值肯定都大于它们俩个,出栈导致的现在相邻
*/
int CurMax(stack<int>&scon, vector<int>&v, int target,int &ret)
{
int k = 0;
int j = 0;
while (!scon.empty())
{
j = scon.top();
scon.pop();
if (!scon.empty())
{
k = scon.top();
}
else
{
k = -1;
}
if (k == -1 || v[k] < v[target])
{
int temp = (target - k - 1)*v[j];
ret = ret>temp ? ret : temp;
break;
}
}
return ret;
}
int sum_max(vector<int>&v)
{
int ret = 0;
stack<int> scon;
int size = v.size();
for (int i = 0; i < size;++i)
{
if (!scon.empty()&&v[scon.top()]<v[i])
{
scon.push(i);
continue;
}
else
{
CurMax(scon, v, i,ret);
}
scon.push(i);
}
int k = -1, j = 0;//-1是因为如果还剩下元素,有俩种情况第一种所有元素都在栈中,第二种执行过出栈处理那么,栈中最后剩余的元素,最后j的元素值肯定都比前面的小,所以面积从0开始算K=-1
/*这里是因为虽然数组遍历完了,但是如果还有元素,我们要计算最后一个面积*/
if(!scon.empty())
{
while (!scon.empty())
{
j = scon.top();
scon.pop();
}
int temp = (size - k - 1)*v[j];
ret = ret>temp ? ret : temp;
}
return ret;
}
int maxArray(vector<vector<int>>&v)
{
int m = v.size();
int n = v[0].size();
vector<int> height(n);
int ret = 0;
int curmax = 0;
for (int i = 0; i < m;i++)
{
for (int j = 0; j < n; j++)
{
height[j] = (v[i][j] == 0) ? 0 : height[j]+1;
}
curmax = sum_max(height);
ret = curmax>ret ? curmax : ret;
}
return ret;
}