题目:
给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中, 最大的矩形区域为1的数量。
示例1:
输入:
1 1 1 0
输出:
3
示例2:
输入:
1 0 1 1
1 1 1 1
1 1 1 0
输出:
6
解题思路:
这个题是单调栈的应用。那么什么是单调栈呢?
单调栈分为单调递增栈和单调递减栈,通过使用单调栈我们可以访问到下一个和上一个 比他大(小)的元素。也就是说在队列或数组中,我们需要通过比较前后元素的大小关系来解决问题时我们通常使用单调栈。
下面这个问题我们就可以用单调栈解决。参考博客
我们可以想象每个直方图里面有一个和直方图高度一样的竹竿,我们拿着竹竿向右移动,遇到比竹竿短的我们会卡住。这时这个直方图的最大面积就是它自己。如果竹竿可以移动,那么最大面积就是竹竿移动的距离和竹竿的高度相乘。
具体代码如下:
import java.util.Stack;
public class 求最大子矩阵的大小 {
public static int maxRecSize(int[][] map) {
if (map == null || map.length == 0 || map[0].length == 0) {
return 0;
}
int l = map[0].length;
int[] height = new int[l];
int maxArea = 0;
//从第一行开始计算最大直方图的面积并依次相加
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < l; j++) {
height[j] = map[i][j] == 0 ? 0 : height[j] + 1;
}
maxArea = Math.max(maxRecFromBottom(height), maxArea);
}
return maxArea;
}
// 给定一个数组,算出这个矩阵的直方图最大的矩形面积
public static int maxRecFromBottom(int[] height) {
if (height.length == 0 || height == null)
return 0;
int maxArea = 0;
int len = height.length;
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < len; i++) {
//如果栈不为空,竹竿遇到比自己小的直方图
while (!stack.isEmpty() && height[i] <= height[stack.peek()]) {
int j = stack.pop();//竹竿弹出
int k = stack.isEmpty() ? -1 : stack.peek();//竹竿移动的左边界
int curArea = (i - k - 1) * height[j];//竹竿移动的面积
maxArea = Math.max(curArea, maxArea);
}
stack.push(i);
}
//当遍历完数组之后,栈中还有元素时,竹竿的右边界为数组的长度
while (!stack.isEmpty()) {
int j = stack.pop();
int k = stack.isEmpty() ? -1 : stack.peek();//竹竿移动的左边界
int curArea = (len - k - 1) * height[j];
maxArea = Math.max(curArea, maxArea);
}
return maxArea;
}
//测试
public static void main(String[] args) {
// int[][] map = { { 1, 1, 1, 0 } };
int[][] map = { { 1, 1, 0, 1 }, { 1, 1, 1, 1 },{ 1, 1, 1, 0 }};
int res = maxRecSize(map);
System.out.println(res);
}
}