【Maximal Rectangle】cpp

题目:

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.

代码:

class Solution {
public:
        int maximalRectangle(vector<vector<char> >& matrix)
        {
            if (matrix.empty()) return 0;
            const int ROW = matrix.size();
            const int COL = matrix[0].size();
            vector<int> height(COL,0);
            vector<int> l_most(COL,0);
            vector<int> r_most(COL,COL-1);
            int max_area = 0;
            for ( int i = 0; i < ROW; ++i )
            {
                int l_curr = 0;
                int r_curr = COL-1;
                // calculate current row's height
                for ( int j = 0; j < COL; ++j )
                {
                    height[j] = matrix[i][j]=='1' ? height[j]+1 : 0;
                }
                // from left to right
                for ( int j = 0; j < COL; ++j )
                {
                    if ( matrix[i][j]=='1' )
                    {
                        l_most[j] = std::max(l_most[j], l_curr);
                    }
                    else
                    {
                        l_most[j] = 0;
                        l_curr = j+1;
                    }
                }
                // from right to left
                for ( int j = COL-1; j>=0; --j )
                {
                    if ( matrix[i][j]=='1' )
                    {
                        r_most[j] = std::min(r_most[j], r_curr);
                    }
                    else
                    {
                        r_most[j] = COL-1;
                        r_curr = j-1;
                    }
                }
                // calculate area of rectangle
                for ( int j = 0; j<COL; ++j )
                {
                    max_area = std::max(max_area, (r_most[j]-l_most[j]+1)*height[j]);
                }
            }
            return max_area;
        }
};

tips:

学习了网上的O(m×n)时间复杂度的解法。

这道题的路子类似于http://www.cnblogs.com/xbf9xbf/p/4499450.html

总体的思路如下:

每次遍历一行的元素,以这一行作为X轴;模仿largest rectangle in histogram这道题

大体思路如下,需要对largest rectangle in histogram这道题有比较深刻的理解

a) 计算每个点的当前高度

b) 计算当前高度下每个点能往左推到哪个位置

c) 计算当前高度下每个点能往右推到哪个位置

d) 遍历以当前行作为X轴可能获得的最大面积

a)~d)走完所有行,就可以获得最大的矩形面积

 

思路实在精妙,详细记录下思考每个环节的过程:

a) 如何计算当前点的高度?

利用滚动数组技巧:height[j]记录的是到i-1行该列对应的高度;如果matrix[i][j]=='1',则height[j] += 1,即比上一行该列位置+1;如果matrix[i][j]=='0'则对于第i行来说,该列对应的高度就是0。这个道理比较直观,简单说就是滚动数组height[j]的更新原则是看高度能不能在新的一行续上。这种滚动数组技巧的好处在于只需要维护一个一维数组,否则需要维护二维数组,是dp过程的常用技巧。

b) c) 如何找每个点向左(右)能推到的最远的位置?

这个部分更是精妙,不仅利用了滚动数组的技巧,而且还充分利用了上一轮dp的结果。以b)为例分析,c)同理。

在此题的背景下,当前行的某列能向左推到哪要考虑如下几种情况:

  1)高度是是0(即matrix[i][j]=='1'不成立):显然能推到最左侧即0的位置,不受上一行该列能向左推到哪的影响。

  2)如果高度不是0(即matrix[i][j]=='1'成立),则这当前行该列能向左推到哪取决于左侧第一个不比它高的列在哪?

    考虑一个问题:在matrix[i][j]=='1'的前提下,第i行的l_most[j]可不可能比第i-1行的l_most[j]还小(即还往左)?

    显然,这是不可能的。因为第i行的j列已经把高度续上了,当且仅当第i行l_most[j]~j列的位置都满足高度续上的前提下,第i行的l_most[j]才可能等于第i-1行的l_most[j];一旦第i行l_most[j]~j有一个位置没有续上高度,那么第i行的l_most[j]就要比第i-1行的l_most[j]小了.

   通过以上分析,在第i行j列已经把高度续上的前提下,能向左推到哪,关键取决于在j左边且最靠近j列没续上高度的列,是否影响到了l_most[j]~j。因此,维护一个l_curr,标记到当前列为止,续上高度的列最多可能向左推到哪。

   所以,需要比较l_most[j]与l_curr的位置。如果遇上了高度为0的,则自动把l_curr+1;如果高度不为0的,判断l_curr是否影响到了l_most[j]

   描述的比较绕口,但是客观上也就是这样了。

d) 计算可能的最大高度

这个就是个常规的dp,不再赘述了。注意一点就是(right-left+1)*height,这里是否“+1”取决于l_most和r_most的取值方式。

==============================================

第二次过这道题,思路记得比较清晰;具体操作上一些细节再熟练一下。

class Solution {
public:
        int maximalRectangle(vector<vector<char> >& matrix)
        {
            int ret = 0;
            if ( matrix.empty() ) return ret;
            vector<int> height(matrix[0].size(), 0);
            for ( int i=0; i<matrix.size(); ++i )
            {
                // update height
                for ( int j=0; j<matrix[i].size(); ++j )
                {
                    height[j] = matrix[i][j]=='0' ? 0 : height[j]+1;
                }
                // update max area
                ret = max(ret, Solution::maxArea(height));
            }
            return ret;
        }
        static int maxArea(vector<int>& height)
        {
            int ret = 0;
            height.push_back(0);
            stack<int> sta;
            for ( int i=0; i<height.size(); ++i )
            {
                if ( sta.empty() || height[i]>height[sta.top()] )
                {
                    sta.push(i);
                    continue;
                }
                while ( !sta.empty() && height[sta.top()]>=height[i] ) 
                {
                    int tmp = sta.top();
                    sta.pop();
                    if ( sta.empty() )
                    {
                        ret = max( ret, i*height[tmp] );
                    }
                    else
                    {
                        ret = max(ret, (i-sta.top()-1)*height[tmp] );
                    }
                }
                sta.push(i);
            }
            height.pop_back();
            return ret;
        }
};

 

转载于:https://www.cnblogs.com/xbf9xbf/p/4545814.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值