题目:
给定一个矩形矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
例如:1 0 1 1
1 1 1 1
1 1 1 0
其中,最大的矩形区域有6个1,所以返回6.
思路:将问题的整个矩阵分成以每行为底的分问题,从上至下,先是以第一行为底,第一行是一个一维数组,这里还是要用到单调栈的概念,从数组开头开始扫描他右边比她小的到他左边比她小的数之间的距离,然后就能求出第一行的最大为1的子数组大小,然后以第二行为底,这里还要用到压缩矩阵的概念,这里规定:此行每个元素向上遍历,若遇到1,继续向上,遇到0停止,则次元素值为连续1的和,若次元素为0,则不向上遍历,此元素值定为0,遍历完毕后,第二行矩阵压缩完毕,同第一行一样是个一维数组,则也跟第一行一样处理。依次继续第三行,第四行,直到整个数组遍历完毕。主要要理解局部单调栈向左右扩的概念。
注释:单调栈:顾名思义,栈里元素是单调递增(不存在相等)或单调递减的,实现:以从栈顶到栈底依次增大为例,每次入栈当符合从栈顶到栈底依次增大,那就依次入栈,否则栈顶元素出栈,引起栈顶元素出栈的是将要入栈的元素,则栈顶元素右边离他最近的比它小的数就是将要入栈的元素,左边离它最近比她小的数就是他栈下面的元素,若栈空,没有数了,那么栈顶元素就左边就没有比他小的数,最后还要依次pop栈。
public static void main(String[] args) {
int[][] map = { { 1, 0, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 0 }, };
System.out.println(maxRecSize(map));
}
public static int maxRecSize(int[][] map){
if (map == null || map.length == 0 || map[0].length == 0) {
return 0;
}
int maxArea=0;
int[] height=new int[map[0].length];
for (int i=0;i<map.length;i++){
for (int j=0;j<map[0].length;j++){
height[j] = map[i][j] == 0 ? 0 : height[j] + 1;
}
maxArea=Math.max(maxRectFromBottom(height),maxArea);
}
return maxArea;
}
public static int maxRectFromBottom(int[] height){
if (height == null || height.length == 0) {
return 0;
}
int maxArea=0;
//单调栈
Stack<Integer> stack=new Stack<Integer>();
for (int i=0;i<height.length;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(maxArea,curArea);
}
stack.push(i);
}
//遍历完数组,处理栈里剩余的元素,此时栈底元素最小,即j位置
while (!stack.isEmpty()) {
int j=stack.pop();
int k=stack.isEmpty()?-1:stack.peek();
int curArea=(height.length-k-1)*height[j];
maxArea=Math.max(maxArea,curArea);
}
return maxArea;
}