思路在笔记十六——单调栈结构中进行了介绍,也附了代码,此处只进行代码的详细解释:
//此处是解决这个题目的整体思路,利用遍历将height写入到数组之中
//再利用数组求出该直方图数组中的面积值和当前的最大值进行比较
//从而去寻找每一层中的数值,最后遍历完每一层之后返回整体的最大值,完成求解
public static int maxRectSize(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++){
//如果j的位置为0,则将整个高度变为0,否则就在原来的长度基础上加1
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 == null || height.length ==0){
return 0;
}
int maxArea = 0;
Stack<Integer> stack = new Stack<Integer>();
for(int i = 0;i<height.length;i++){
//只要当前数值小于栈顶数据,则意味着当前数值是较小的数据,
// 从而将之前的数据进行计算,此时就是单调栈的结构
// 存入到栈中的数据因为哪个数据弹出则意味着该数据在范围内最小到i处停止
//j位置为最低高度的左边界就是k,为左边离的最近的小于j高度的值。
while(!stack.isEmpty() && height[i] <= height[stack.peek()]){
//第一次循环j=0,k表示弹出之后底下的下标,如果没有东西则为-1.
int j = stack.pop();
int k = stack.isEmpty() ? -1:stack.peek();
//所以此时i位置上不满足height[j]最小,k位置上不满足height[j]最小
// 所以此时总长度为(i-1)-k
// 如果栈中没数据,则意味着从0开始都满足,所以-1位置上不满足,让此时k为-1
int curArea = (i-k-1)*height[j];
maxArea = Math.max(maxArea,curArea);
}
stack.push(i);
}
//最后栈中剩余的元素从上向下为单调递减的形式
while(!stack.isEmpty()){
int j = stack.pop();
int k = stack.isEmpty() ? -1:stack.peek();
//此时进行计算的时候需要注意的是数组最后到第k位置中必定没有比height[j]小的数值
//不然该数值不会到最后还保存,而是提前因为最后较小的值而弹出
//所以此时求解数值从总长度减去(k+1)长度,此段长度为满足最小高度为height[j]的数值。
int curArea = (height.length-k-1)*height[j];
maxArea = Math.max(maxArea,curArea);
}
return maxArea;
}
可以看到这道题整体还是使用了单调栈的思想,利用左边和右边离的最近的大于或小于当前数值的位置,从而求解出形成矩形的面积。