算法学习之动态规划(leetcode 85. Maximal Rectangle)

0x01题目
85. Maximal Rectangle

Given a 2D binary matrix filled with 0's and 1's,  find the largest rectangle containing only 1's and return its area.

For example, given the following matrix:

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

Return 6.
0x02解析

使用动态规划的思想去解决这个问题,自己总结的动态规划三要素:定义概念边界初始化一般情况递推,两个难点是:角标索引问题递推情况剖析
cur_left定义为在一个字符数组中,当前元素可以延伸到最左边元素的下标(当前元素为0,则这个值为0)。如在字符数组"0111001110",对第三个1,其cur_left=1,对最后一个0,其cur_left=0。其示意图如下图所示
这里写图片描述
cur_right定义为在一个字符数组中,当前元素可以延伸到最右边元素的下标+1(当前元素为0,则这个值为字符数组的长度)。如在字符数组"0111001110",对第四个1,其cur_right=8+1,对第一个0,其cur_right=10,其示意图如下图所示
这里写图片描述
总结cur_leftcur_right均由当前行的值来确定。如果当前值为'1',则cur_leftcur_right均不变;如果当前值为'0',则cur_left值为当前元素右侧,cur_right值为当前元素位置。(左闭右开)
left[i][j]定义为在第i行第j列处,可以延伸到最左边元素的下标。
right[i][j]定义为在第i行第j列处,可以延伸到最右边元素的下标+1。
核心思路是从第一行开始一行一行地处理,使[i, j]处最大子矩阵的面积是(right(i, j)-left(i, j))*height(i, j)。其中height统计当前位置及往上'1'的数量;leftright是高度是当前点的height值的左右边界,即是以当前点为中心,以height为高度向两边扩散的左右边界。

left(i,j) = max(left(i-1,j), cur_left)

right(i,j) = min(right(i-1,j), cur_right)

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

leftrightheight的值均可以通过前一行和当前行的值来确定,因此,逐行遍历即可。

举例说明。字符长方形如下:

0 0 0 1 0 0 0 
0 0 1 1 1 0 0 
0 1 1 1 1 1 0

leftl)、rightr)和heighth)的值如下所示

row 0:
    l: 0 0 0 3 0 0 0
    r: 7 7 7 4 7 7 7
    h: 0 0 0 1 0 0 0
row 1:
    l: 0 0 2 3 2 0 0
    r: 7 7 5 4 5 7 7 
    h: 0 0 1 2 1 0 0 
row 2:
    l: 0 1 2 3 2 1 0
    r: 7 6 5 4 5 6 7
    h: 0 1 2 3 2 1 0
0x03代码
public class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix == null || matrix.length == 0 || matrix[0] == null) return 0;

        int m = matrix.length, n = matrix[0].length;
        int[] l = new int[n];
        int[] r = new int[n];
        int[] h = new int[n];
        int result = 0;

        for(int i = 0; i < n; i++){
            l[i] = 0;
            r[i] = n;
            h[i] = 0;
        }
        for(int i = 0; i < m; i++){
            int cur_left = 0, cur_right = n;
            for(int j = 0; j < n; j++){
                if(matrix[i][j] == '1') h[j] += 1;
                else                    h[j] = 0;
//              System.out.print(h[j]);
//              System.out.print(" ");
            }
            for(int j = 0; j < n; j++){
                if(matrix[i][j] == '1'){
                    l[j] = Math.max(l[j], cur_left);
                }
                else{
                    l[j] = 0;
                    cur_left = j + 1;
                }
//              System.out.print(l[j]);
//              System.out.print(" ");
            }
            for(int j = n-1; j >= 0; j--){
                if(matrix[i][j] == '1'){
                    r[j] = Math.min(r[j], cur_right);
                }
                else{
                    r[j] = n;
                    cur_right = j;
                }
//              System.out.print(r[j]);
//              System.out.print(" ");
            }
            for(int j = 0; j < n; j++){
                result = Math.max(result, (r[j] - l[j]) * h[j]);
            }
            System.out.println();
        }

        return result;
    }
}

参考 https://discuss.leetcode.com/topic/6650/share-my-dp-solution
参考 http://blog.csdn.net/makuiyu/article/details/44857479

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值