zoukankan      html  css  js  c++  java
  • [LeetCode] Maximal Rectangle

    (Version 1.0)

    在做这道题之前,我刚刚做了Scramble String(http://www.cnblogs.com/icecreamdeqinw/p/4338731.html),所以Maximal Rectangle这道题拿来之后我的想法自然跟着惯性觉得肯定是可以用一个三维DP的解法做的,至于时间和空间复杂度能不能通过LeetCode OJ就不好说了。

    (一)无脑的三维DP

    为了熟悉一下刚刚习得的三维DP的思路样板,先写了一个利用一个三维数组isLine[i][j][k]来保存第i行开头为第j个结尾为第k个元素是否能构成一个全由'1'组成的一条水平线,外层按照线的长度由短到长循环,中间循环这条线的起始位置,然后最内层按照由上至下的顺序移动这条线,这个代码的时间和空间复杂度很高,但是没想到通过了LeetCode OJ,代码如下:

     1 public class Solution {
     2     public int maximalRectangle(char[][] matrix) {
     3         if (matrix.length == 0) {
     4             return 0;
     5         }
     6         boolean[][][] isLine = new boolean[matrix.length][matrix[0].length][matrix[0].length];
     7         for (int i = 0; i < matrix.length; i++) {
     8             for (int j = 0; j < matrix[0].length; j++) {
     9                 if (matrix[i][j] == '1') {
    10                     isLine[i][j][j] = true;
    11                 }
    12             }
    13         }
    14         int result = 0;
    15         for (int i = 0; i < matrix.length; i++) {
    16             for (int l = 2; l <= matrix[0].length; l++) {
    17                 for (int j = 0; j <= matrix[0].length - l; j++) {
    18                     int end = j + l - 1;
    19                     if (matrix[i][end] == '1' && isLine[i][j][end - 1]) {
    20                         isLine[i][j][end] = true;
    21                     }
    22                 }
    23             }
    24         }
    25         for (int l = 1; l <= matrix[0].length; l++) { // length of the line
    26             for (int i = 0; i <= matrix[0].length - l; i++) { // start point of the line
    27                 int bound = i + l - 1;
    28                 int area = 0;
    29                 for (int j = 0; j < matrix.length; j++) { // row #
    30                     if (isLine[j][i][bound]) {
    31                         area += l;
    32                         result = Math.max(result, area);
    33                     } else {
    34                         area = 0;
    35                     }
    36                 }
    37             }
    38         }
    39         return result;
    40     }
    41 }

    这个代码虽然通过了LeetCode OJ,可是实际上是因为这一题给的时间限制非常宽松,大多数通过的Java代码要比这个代码耗时少一半以上,说明这个解法一定不是一个好的解法,需要从不同的思路去优化之。

    (二)优化

    在用上文提到的无脑三维DP通过OJ之后,看到了LeetCode对于这道题的分类标签中有Stack,想到了也许可以用类似Largest Rectangle in Histogram中使用Stack存储边界的方法,在用不同长度的边从上向下扫的时候,可以不死板地按照长度由小到大进行循环。另外考察上文中代码的循环顺序会发现这其实是一个不cache friendly的代码,因为最内层每次循环时变化的都是第一个下标,所以如果我们把扫的方向从垂直改成水平,并且把三维DP数组改成存垂直线,也许会有性能上的提升。

    在看过别人的答案之后,发现原来这道题是Largest Rectangle in Histogram的扩展题,如果我们维护一个二维数组height[][],height[i][j]表示当前矩形中从上边到(i, j)点的距离的话,实际上就是在做matrix.length次Largest Rectangle in Histogram。这里先贴上自己写的代码,随后细说:

     1 public class Solution {
     2     public int maximalRectangle(char[][] matrix) {
     3         if (matrix.length == 0) {
     4             return 0;
     5         }
     6         int[][] height = new int[matrix.length][matrix[0].length];
     7         for (int i = 0; i < matrix[0].length; i++) {
     8             height[0][i] = matrix[0][i] == '1' ? 1 : 0; 
     9         }
    10         for (int i = 1; i < matrix.length; i++) {
    11             for (int j = 0; j < matrix[0].length; j++) {
    12                 height[i][j] = matrix[i][j] == '1' ? height[i - 1][j] + 1 : 0;
    13             }
    14         }
    15         int result = 0;
    16         for (int i = 0; i < matrix.length; i++) {
    17             Stack<Integer> stack = new Stack<>();
    18             for (int j = 0; j < matrix[0].length; j++) {
    19                 while (!stack.empty() && height[i][j] < height[i][stack.peek()]) {
    20                     result = Math.max(result, height[i][stack.pop()] * (stack.empty() ? j : j - stack.peek() - 1));
    21                 }
    22                 stack.push(j);
    23             }
    24             while (!stack.empty()) {
    27                 result = Math.max(result, height[i][stack.pop()] * (stack.empty() ? matrix[0].length : matrix[0].length - stack.peek() - 1));
    28             }
    29         }
    30         return result;
    31     }
    32 }

    (待续)

  • 相关阅读:
    FAQ接口自动化_转载参考
    FAQ接口自动化_报错解决
    SpringBootRESTfulAPI平台项目-演示版01
    SpringBoot08_mysql操作
    SpringBoot07_RESTful API:获取girls表的内容
    SpringBoot06_程序自动化创建/更新数据库里的表信息
    mysqldump
    js 原型链
    node.js 事件发射器模式
    codeblocks 支持c++11
  • 原文地址:https://www.cnblogs.com/icecreamdeqinw/p/4338732.html
Copyright © 2011-2022 走看看