85. Maximal Rectangle(最大矩形)

85.Maximal Rectangle

从0 1矩阵中求解最大矩形面积,博主在看到这个题目的时候第一反应就是暴力,没有暴力解决不了的问题,但是一定会超时,而且也是非常不好的解决方案,有没有什么比较好的思路呢,Mark一下讨论区中的DP解法。只能说看到DP解法的时候热血沸腾,居然还可以这样子,废话不多说。

首先我们定义三个辅助数组,height [ ], left [ ], right [ ]。这三个数组什么作用呢。
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]

策略: 把matrix看成多个直方图, 每一行及其上方的数据都构成一个直方图, 需要考察matrix.size()个直方图
对于每个点(row, col), 我们最后都计算以这个点上方的连续的’1’往left, right方向延申可以得到的最大的矩形的面积
通过这种方法获取的矩形一定会把最大的矩形包含在内
height[row][col]记录的是(row, col)这个坐标为底座的直方图柱子的高度, 如果这个点是’0’, 那么高度当然是0了
left[row][col]记录的是(row, col)这个坐标点对应的height可以延申到的最左边的位置
right[row][col]记录的是(row, col)这个坐标点对应的height可以延申到的最右边的位置+1
以上面的matrix为例,
对于(row=2, col=1)这个点, left=0, right=5, height=1
对于(row=2, col=2)这个点, left=2, right=3, height=3
(2,2)这个点与(2,1)紧挨着,left和right却已经变化如此之大了, 这是因为left和right除了受左右两边的’1’影响, 还受到了其上方连续的’1’的制约
由于点(2,2)上有height=3个’1’, 这几个’1’的left的最大值作为当前点的left, 这几个’1’的right的最小值作为当前点的right
因此, 实际上, 我们是要找以hight对应的这条线段往左右两边移动(只能往全是’1’的地方移动), 可以扫过的最大面积
当hight与目标最大矩形区域的最短的height重合时, 最大矩形的面积就找到了, 如上面的例子, 就是点(2,3)或(2,4)对应的height

也就是每一个height[i]它所等到达的最左边和最右边的界限哪里,那么通过循环遍历所有情况则得到答案。
代码:

class Solution {
public:
	int maximalRectangle(vector<vector<char>>& matrix) {
		int m = matrix.size();
		if (m == 0)
			return 0;
		int n = matrix[0].size();
		vector<int>height(n, 0);vector<int>left(n, 0);vector<int>right(n, 0);
		int area = 0, res = 0, sum = 0;
		for (int i = 0; i < m; i++)
		{
			for (int j = 0; j < n; j++)
			{
				if (matrix[i][j] == '1')
					height[j]++;
				else
					height[j] = 0;
			}
			for (int j = 0; j < n; j++)
			{
				if (matrix[i][j] == '1')
				{
					int k = j;
					while (k >= 0)
					{
						if (height[k] >= height[j])
							k--;
						else
							break;
					}
					left[j] = k + 1;
				}
				else
				{
					left[j] = j;
				}
			}
			for (int j = 0; j < n; j++)
			{
				if (matrix[i][j] == '1')
				{
					int k = j;
					while (k < n)
					{
						if (height[k] >= height[j])
							k++;
						else
							break;
					}
					right[j] = k - 1;
				}
				else
					right[j] = j;
			}
			for (int j = 0; j < n; j++)
			{
				area = height[j] * (right[j] - left[j] + 1);
				sum = max(area, sum);
			}
			res = max(res, sum);
		}
		return res;
	}
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值