求最大子矩阵的大小

题目描述

给你一个矩阵,这个矩阵的值不是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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值