题目
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
思路
前缀和+单调栈
本题把每一层看成是一个柱状图,可以转化成代码随想录——柱状图中最大的矩形(双指针&动态规划&单调栈)
如下图的橙色部分,就可以完全转化成柱状图中最大的矩形
每一层看作是柱状图,注意:一定要是连续的1
第一层柱状图的高度[“1”,“0”,“1”,“0”,“0”],最大面积为1;
第二层柱状图的高度[“2”,“0”,“2”,“1”,“1”],最大面积为3;
第三层柱状图的高度[“3”,“1”,“3”,“2”,“2”],最大面积为6;
第四层柱状图的高度[“4”,“0”,“0”,“3”,“0”],最大面积为4(这里要注意,因为第1列和第2列遇到了0,没有之前的1不会继续统计);
接下来只需要求出每一层的height[i]
然后传递给柱状图中最大的矩形中的函数即可
java代码如下:
//单调栈 + 哨兵模式
class Solution {
public int maximalRectangle(char[][] matrix){
int col = matrix[0].length;
int[] height = new int[col + 2];//申请一个新数组,长度是矩阵的列数+2,分别头尾补0,即两个哨兵,数组的内容记录的是每一层的高度
//在左右两侧添加两个哨兵
height[0] = 0;//左侧的哨兵使得不用判空
height[col + 1] = 0;//右侧的哨兵能够保证在遍历结束时弹出前面的柱子计算面积
Stack<Integer> stack = new Stack<>();
int maxArea = 0;//记录最大面积
for(int row = 0; row < matrix.length; row++){//遍历矩阵中的每一行元素
for(int i = 0; i < col; i++){//遍历列
if (matrix[row][i] == '1'){//如果当前元素是1,那么当前列的高度+1
height[i + 1]++;//因为首位置的哨兵height[0]已经添加过了,所以需要填充的范围是[1,col],所以要用i+1,进行填充,同时这里是统计第row行的每列的高度,然后下一行row+1行继续循环的时候,遍历到相同列会进行累加,最终得到每列的最终高度
} else {//如果当前元素是0,那么高度直接置为0(之前有多少个1都没用,因为不连续了)
height[i + 1] = 0;
}
}
maxArea = Math.max(maxArea,largestRectangleArea(height));//将求出来的高度,传递给柱状图中最大矩形的那个算法中
}
return maxArea;
}
public int largestRectangleArea(int[] height){//本题相当于是这一步的heigh不再由题目给出,而是自己写个函数求出来,并作为参数传递进来
Stack<Integer> stack = new Stack<Integer>();
//数组扩容,头尾各加一个元素,哨兵模式
int[] newHeight = new int[height.length + 2];
newHeight[0] = 0; //左侧的哨兵使得不用判空
newHeight[newHeight.length -1] = 0;//右侧的哨兵能够保证在遍历结束时弹出前面的柱子计算面积
for(int i = 0; i < height.length; i++){
newHeight[i + 1] = height[i];
}
height = newHeight;
stack.push(0);
int result = 0;
for(int i = 1; i < height.length; i++){
if(height[i] >= height[stack.peek()]){
stack.push(i);
} else {
while(!stack.isEmpty() && height[i] < height[stack.peek()]){
int mid = stack.pop();
int left = stack.peek();
result = Math.max(result, height[mid] * (i - left - 1));
}
stack.push(i);
}
}
return result;
}
}