左神算法进阶class2—单调栈应用2:求最大子矩阵

左神算法进阶class2—单调栈应用2:求最大子矩阵

1.题目:单调栈应用2:求最大子矩阵

给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
例如:
1 1 1 0
其中,最大的矩形区域有3个1,所以返回3。再如:
1 0 1 1
1 1 1 1
1 1 1 0
其中,最大的矩形区域有6个1,所以返回6。

2.分析

本题同样可以用单调栈的思想解题,左神算法进阶class2—单调栈应用:直方图中矩形的最大面积 做为本题的引子,如果上一题不了解,本题可能会看不懂,因为本题是在上一题的基础上修改得来的。
在求直方图面积中,杆子的底侧都在同一水平线,而本题不一定从底侧开始,想一个极端情况,左上角的1,它可以单独作为一个杆子进行滑动。(0用鼠标画的真的好丑!)
在这里插入图片描述
也就是说每一行的1都可以作为杆子进行滑动,好了,我们首先可以考虑设置三条平行线,第一条只包含一行,第二条包含上两行,第三条基准线相当于直方图包含所有的值。本题是不是可以分解为把三个基准中所有的杆子进行扫略,最后求最大值。
在这里插入图片描述
如果到这里还没明白的朋友还是建议看下上一题哦。
好像是可行的!但是问题又来了,对于下图中间出现的0,相当于我们的杆子被打断了,该怎么解决呢。
在这里插入图片描述
我们可以设置一个长度为列的数量的辅助数组help,表示此位置向上有多少个连续的1。首先对于最上面的水平线,单独拎出来。如下图,简化为1,0,1,1。其中第一个1表示在当前0位置,向上有1个1。那么直方图就构成了,1,0,1,1求直方图的最大面积,这一步是可解的也是容易做的,完全是上一题的部分。
在这里插入图片描述
可能大家还比较疑惑,我们再来看第二条平行线。下图蓝线为基准线,辅助数组help更新为2,1,2,2,第一个2表示在当前列,向上有连续两个1,所以值为2。同样,辅助数组就变成直方图,计算2,1,2,2的最大矩形。可是,有朋友可能会问为什么辅助数组要表示此位置向上有多少个连续的1?直接是累加不行吗?别急,请再往下看。
在这里插入图片描述
现在我们开始计算第三条基准线啦,直接累加好像是3,2,3,2,咦,为什么最后一个是0?原来我们最初的设置基准线的目的就是从基准线开始滑动的杆子,如果是0的话,当然杆子就不存在了。
在这里插入图片描述
我们实际的杆子是从基准线开始的
在这里插入图片描述
是的,在上一题中,直方图都是从底部开始的,而本题每一个1都可以作为杆子进行滑动,所以我们设置三基准线,就囊括了所有的杆子可能的滑动,而不是只在底侧进行扫略。
下图是所有的杆子及对应的直方图
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.核心代码

现在我们回头看辅助数组到底是怎么设置的,help表示此位置向上有多少个连续的1,如果当前位置是0,上面的1就没有用了,因为杆子只从当前基准进行计算,如果不是0是1呢,那么辅助数组在当前位置就是上一行辅助数组值再加一help[j] = mp[i][j] == 0 ? 0 : help[j] + 1;。因为上一行同一位置已经统计了,只需要加一即可。
我们对整个数组按行进行遍历,统计出每行的辅助数组,再调用计算同一水平线求直方图面积的函数,找到最大值就是本题的结果。

int maxRecSize(vector<vector<int> > mp)
{
   
	if (mp.size() == 0 || mp[0].size() == 0)	return 0;
	vector<int> help(mp[0].size());
	int maxArea = 0;
	for (int i = 0; i < mp.size(); i++)
	{
   
		for (int<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值