***[Lintcode]最大矩形

类似于蓄水池问题,首先创造一个矩形,记录每一列上true的数量。

[
  [1, 1, 0, 0, 1],
  [0, 1, 0, 0, 1],
  [0, 0, 1, 1, 1],
  [0, 0, 1, 1, 1],
  [0, 0, 0, 0, 1]
]
可转换为:

[
  [1, 1, 0, 0, 1],
  [0, 2, 0, 0, 2],
  [0, 0, 1, 1, 3],
  [0, 0, 2, 2, 4],
  [0, 0, 0, 0, 5]
]
第一种方案:a[i][j]=min(a[i][j-1],matrix[i][k])×矩阵长度。  但是如果为递增的阶梯形时,会多算很多1. 因为a[i][j-1]不能代表以a[i][j-1]为右下脚的矩阵对高度。

第二种:记录每一行最小值和连续不为0的长度,然后和matrix[i][j]比较求最大面积。同样不可行,递增阶梯形时会出问题。

第三种方案:看来只能用Largest Rectangle in Histogram的方法,使用stack。维护一个stack,stack储存index,元素的高度递增。为什么是递增的?可以准确确定最小高度,及适用长度(从当前index到end)。递减也可以。但必须保证单调性。每次遇到递减时,为什么可以pop?因为遇到递减时,则代表遇到峰值,遇到峰值时,我们可以确定其包含的最大矩阵的右边界。其左边界也可以根据stack.peek确定。


如图为当前指针走到index=4时,出现递减情况,则第一张图是stack出栈,然后根据stack中前一个值以及index位置确定左右边界,根据stack中当前值确定高度。

第一张图:stack: 0,1,2.   index=3   面积等于(3-1-1) * 5=5 如图绿色部分

第二张图:stack:0,1     index=3 面积为(3-0-1)*3=6 如图绿色部分




public class Solution {
    /**
     * @param matrix a boolean 2D matrix
     * @return an integer
     */
    public int maximalRectangle(boolean[][] s) {
        int height = s.length;
        if(height == 0) return 0;
        int width = s[0].length;
        if(width == 0) return 0;
        
        int[][] matrix = new int[height][width];
        
        for(int i = 0; i < height; i++) {
            for(int j = 0; j < width; j++) {
                if(i > 0)
                    matrix[i][j] = s[i][j] == true ? matrix[i - 1][j] + 1 : 0;
                else 
                    matrix[i][j] = s[i][j] == true ? 1 : 0;
            }
        }
        
        int res = 0;
        for(int i = 0; i < height; i++) {
            res = Math.max(res, getSquare(i, matrix));
        }
        return res;
    }
    
    private int getSquare(int i, int[][] matrix) {
        int res = 0;
        Stack<Integer> stack = new Stack<Integer>();
        for(int j = 0; j < matrix[0].length; j++) {
            if(stack.isEmpty() || matrix[i][j] > matrix[i][stack.peek()]) {
                stack.push(j);
            } else {
                int top = stack.peek();
                while(matrix[i][top] >= matrix[i][j]) {
                    stack.pop();
                    int length = stack.isEmpty() ? j : j - stack.peek() - 1;
                    res = Math.max(res, matrix[i][top] * length);
                    if(stack.isEmpty()) {
                    	break;
                    }
                    top = stack.peek();
                }
                stack.push(j);
            }
        }
        while(!stack.isEmpty()) {
            int top = stack.pop();
            int length = stack.isEmpty() ? matrix[0].length : matrix[0].length - stack.peek() - 1;
            res = Math.max(res, matrix[i][top] * length);
        }
        return res;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值