[LeetCode] 85. Maximal Rectangle

题:https://leetcode.com/problems/maximal-rectangle/description/
#题目
Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing only 1’s and return its area.

Example:

Input:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
Output: 6

解法

DP思想,对于每个 i,j 求它的 左右边界和累加的高度然后算法矩形的面积,由于高度为可以累加的,左右边界是继承的,即,上个row的i,j 的边界和现在i,j的边界关系是上个row的边界一定包含当前row边界。
通过左右各次扫描能得出相应的边界。
可以和 [LeetCode] 79. Word Search 对比下
故从上个row中提取最好,可能成为当前row最好的,这就是题目中的状态转移。

https://leetcode.com/problems/maximal-rectangle/discuss/29054/Share-my-DP-solution

The DP solution proceeds row by row, starting from the first row. Let the maximal rectangle area at row i and column j be computed by [right(i,j) - left(i,j)]*height(i,j).

All the 3 variables left, right, and height can be determined by the information from previous row, and also information from the current row. So it can be regarded as a DP solution. The transition equations are:

left(i,j) = max(left(i-1,j), cur_left), cur_left can be determined from the current row

right(i,j) = min(right(i-1,j), cur_right), cur_right can be determined from the current row

height(i,j) = height(i-1,j) + 1, if matrix[i][j]==‘1’;

height(i,j) = 0, if matrix[i][j]==‘0’

The code is as below. The loops can be combined for speed but I separate them for more clarity of the algorithm.

code

class Solution:
    def maximalRectangle(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        m = len(matrix)
        if m == 0:
            return 0
        n = len(matrix[0])
        
        bleft = {}
        bright ={}
        heights = {}
        for i in range(n):
            bleft[i] = -1
            bright[i] = n
            heights[i] = 0
        
        maxm = 0
        for i in range(m):
            cur_left = -1
            cur_right = n
            for j in range(n):
                if matrix[i][j] == "1":
                    bleft[j] = max(bleft[j],cur_left)
                    heights[j] += 1
                else:
                    bleft[j] = -1
                    cur_left = j
                    heights[j] = 0
                    
            for j in range(n-1,0-1,-1):
                if matrix[i][j] == "1":
                    bright[j] = min(bright[j],cur_right)
                else:
                    bright[j] = n
                    cur_right = j
                    
            for j in range(n):
                maxm = max(maxm,heights[j]*(bright[j]-bleft[j]-1))
                
        return maxm

二刷

对于 矩阵的 每个元素 i,j,可以得到获得一种矩阵,这个矩阵是 第 j 列 ,从 第 i 行 向上延申能 获取的 最高高度的 矩阵。
换句话说,对 每个元素 i,j,向上看 可以 看作 是一个 直方图。
可获得 以每列为 矩阵最高 位置的 矩阵大小。

下面的DP 也就是求这个问题。

DP 主要是 针对 左右边界 的 获取。

状态:
int[i][j] heights : 在i,j 位置 向上 直方图的位置。
int[i][j] leftBound: i,j 位置 的左边界。
int[i][j] rightBound: i,j 位置 的右边界。

初始状态:

int[i][j] heights = 0
int[i][j] leftBound =0
int[i][j] rightBound = COL

状态转移:
高度:

            if(matrix[i][j]=='1'){
                height[i][j] = height[i-1][j] + 1;
            }else{
                height[i][j] = 0;
            }

左边界:

            if(matrix[i][j]=='1'){
                leftBound[i][j] = Math.max(leftBound[i-1][j],curLeftBound);
            }else{
                curLeftBound = j + 1; 
                leftBound[i][j] = 0;
            }

右边界:

            if(matrix[i][j]=='1'){
                rightBound[j] = Math.min(rightBound[j],curRightBound);
            }else{
                curRightBound = j;
                rightBound[j]=COL;
            }

由于是 dp[i] 只 依靠 dp[i-1] 所以可以优化。

class Solution {
    public int maximalRectangle(char[][] matrix) {
        int ROW = matrix.length;
        if(ROW == 0)
            return 0;
        int COL = matrix[0].length;
        int[] height = new int[COL];
        int[] leftBound = new int[COL];
        int[] rightBound = new int[COL];
        Arrays.fill(rightBound,COL);
        int res = 0;
        for(int i =0 ; i < ROW ; i++){
            int curLeftBound = 0;
            int curRightBound = COL;
            for(int  j = COL-1;j>=0 ; j--){
                if(matrix[i][j]=='1'){
                    rightBound[j] = Math.min(rightBound[j],curRightBound);
                }else{
                    curRightBound = j;
                    rightBound[j]=COL;
                }
            }
            
            for(int j = 0 ; j <COL ; j++){
                if(matrix[i][j]=='1'){
                    height[j]++;
                    leftBound[j] = Math.max(leftBound[j],curLeftBound);
                    res = Math.max(res,(rightBound[j] - leftBound[j])*height[j]);
                }else{
                    height[j] = 0;
                    curLeftBound = j + 1; 
                    leftBound[j] =0;
                }
                
            }
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值