目录
主干题
力扣085最大子矩形
给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例:
输入:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
输出: 6
解题思路
1、计算每个行和前面所有行叠加所产生的数组里的最大子矩阵,求出最大的数组里的最大子矩阵。叠加规则为遇到1累加,遇到0重新开始计算
2、数组的最大子矩阵实际就是求以j为中心向左右寻找第一个比j柱子小的柱子,然后计算对应的矩形面积后比较大小
如何求arr[j]数组的最大矩形大小
求数组最大矩形大小,我们是利用一个单调栈来实现的。单调栈顾名思义就是栈的元素从栈底到栈顶依次是递增或递减的。利用单调递增栈我们可以求出数组中每一个元素左边离它最近比它小的位置和右边离它最近比它小的位置在哪里。例如对于数组{3,1,3,2,2}对于第一个元素左边离它最近比它小的位置为空,右边离它最近比它小的位置在哪里为1。如何利用单调递增栈实现上述过程呢?在将数组元素压入栈时需要遵循下面的规则:
- 如果当前栈stack为空或者当前数组的元素
arr[j]>arr[stack.top()](栈顶元素)
,那么直接把当前元素的位置j压入stack。 - 如果当前栈不为空且当前数组元素
arr[j]<=arr[stack.top()](栈顶元素)
,那么依次从stack弹出元素,并结算栈顶元素为根基,向左和向右分别可以拓展到哪里,则可以得出当前最大子矩阵的大小为多少。
计算最大矩阵大小思想如下:
如何当前遍历的元素的元素为i,当前栈顶元素元素为j,弹出栈顶元素后,新的栈顶元素为k。那么现在考虑以元素为j为根基,其向左最左能达到k+1,因为j最左最近小于j的元素应该为k,那么向右最远应该能到i-1,因为j之所以被弹出,就是因为遇到了第一个比位置j值小的位置。所以其最大子矩阵大小结算为(i-k-1)*height[j].
代码示例
Java版代码
class Solution {
public int maximalRectangle(char matrix[][]) {
int arr[] = new int[matrix[0].length];
Integer maxSum = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
arr[j] = (matrix[i][j] == '0' ? 0 : arr[j] + 1);
}
maxSum = Math.max(maxSum, getArrMaxSum(arr));
}
return maxSum;
}
private int getArrMaxSum(int[] arr) {
Stack<Integer> stack = new Stack();
Integer j = null;
Integer k = -1;
int max = 0;
for (int i = 0; i < arr.length; i++) {
if(stack.isEmpty() || arr[stack.peek()] < arr[i]){
stack.push(i);
}else{
while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) {
j = stack.pop();
k = stack.isEmpty()? -1:stack.peek();
max = Math.max(max, ((i - 1) - (k + 1) + 1) * arr[j]);
}
stack.push(i);
}
}
//i=arr.length - 1 仍然需要计算栈内剩余数据所构成的组合情况
while (!stack.isEmpty()) {
j = stack.pop();
k = stack.isEmpty() ? -1 : stack.peek();
max = Math.max(max, ((arr.length - 1) - (k + 1) + 1) * arr[j]);
}
return max;
}
}