leetCode85:最大矩形

目录

一、题目描述

二、解题思路

三、代码实现


一、题目描述

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例 1:


输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。

示例 2:

输入:matrix = []
输出:0

示例 3:

输入:matrix = [["0"]]
输出:0

示例 4:

输入:matrix = [["1"]]
输出:1

示例 5:

输入:matrix = [["0","0"]]
输出:0
 

提示:

  • rows == matrix.length
  • cols == matrix[0].length
  • 0 <= row, cols <= 200
  • matrix[i][j] 为 '0' 或 '1'

二、解题思路

这道题之前我没做过84题,所以一开始不会………

看题解的是时候有人说84题类似,就先去做了84题。由于类型是一样的一起记录吧。

84题:柱状图的最大矩形

上图左边的柱状图中的最大面积为右边所描绘的区域。

84思路:

我们先对柱形编号index{0,1,2,3,4,5}、对应高度heights{2,1,5,6,2,3}。以4号柱子为例,4号柱子的高度为2,它所能围成的最大矩形的左边界为2号柱子,右边界为5号柱子,最大面积2*4=8。对每一个柱形都可以这么操作得到最大面积。现在的问题是怎么可以在时间代价小的情况下得到左右边界?

观察发现:左边界是左边第一个高度比当前小的柱形,左边比当前大的都需要跳过(不是边界),很容易想到单调栈的结构,每一个柱形入栈时都把栈顶比当前大的柱形弹出,直到栈顶的高度比当前的低,此时的柱形即是左边界减1位置的柱形。对于右边界可以采取同样的的策略,入栈顺序换成从右到左即可。

细节:这里左右两边都需要一个哨兵,因为会存在这样的情况,当前柱形在其左边的所有柱形中是最小的,此时栈会被弹空,此时的左边界应记为-1,表示是左边所有柱形当中最小的;同理右边的边界是列的大小+1。

85思路:

对于矩阵的每一行中的元素1,计算出现在其左边连续1的数量left[i][j]。比如题目实例1中的第一行的元素的left数组值分别为{1,0,1,0,0},第二行的left数组值为{1,0,1,2,3}…

在求出所有元素的left数组值后,把每一列都看成是一个柱形图,柱形的高度就是left[i][j]的值;依次求完所有列的最大矩形,取最大的矩形面积返回即为结果。

也就是说矩阵中的每一列就是一道84题。

三、代码实现

#include <bits/stdc++.h>
using namespace std;

int maximalRectangle(vector<vector<char>>& matrix) {
	int r = matrix.size();
	if (r == 0) {
		return 0;
	}
	int c = matrix[0].size();
	//求矩阵中每一个元素左边连续1的个数
	vector<vector<int>> left(r, vector<int>(c, 0));
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (matrix[i][j] == '1') {
				left[i][j] = (j == 0 ? 1 : left[i][j - 1] + 1);
			}
		}
	}
	//此处跟84题一模一样处理
	//对每一列转换成柱状图求最大矩形
	int res = 0;
	for (int j = 0; j < c; j++) {
		vector<int> up(r), down(r);
		vector<int> monoSta;
		//求左边高度小于当前的下标
		for (int i = 0; i < r; i++) {
			while (!monoSta.empty() && left[i][j] <= left[monoSta.back()][j]) {
				monoSta.pop_back();
			}
			//左边以-1为哨兵
			up[i] = (monoSta.empty() ? -1 : monoSta.back());
			monoSta.push_back(i);
		}
		monoSta.clear();
		//求右边高度小于当前的下标
		for (int i = r - 1; i >= 0; i--) {
			while (!monoSta.empty() && left[i][j] <= left[monoSta.back()][j]) {
				monoSta.pop_back();
			}
			//左边以r为哨兵
			down[i] = (monoSta.empty() ? r : monoSta.back());
			monoSta.push_back(i);
		}
		for (int i = 0; i < r; i++) {
			//更新每一个矩形的面积
			res = max(res, (down[i] - up[i] - 1)*left[i][j]);
		}
	}
	return res;
}

int main() {
	vector<vector<char> > matrix = { {'1','0','1','0','0'},
	{'1','0','1','1','1'},
	{'1','1','1','1','1'},
	{'1','0','0','1','0'} };


	cout << maximalRectangle(matrix) << " ";

	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值