[leetcode]Maximal Rectangle

这道题也不简单啊。
这道题是在上一题基础上的扩展。可以做到O(n^2)的。首先上一题Largest Rectangle in Histogram有O(n)的解法。
然后计算每一个位置从开始到目前有多少连续的1(假设按列算),这个可以通过O(n^2)做到,因为可以上一个加一,h[i][j-1]+1。
接下来就是遍历每行,要注意的是之前按列算,那么现在要按行遍历。
最后仍然超时!!即使我的代码和http://www.cnblogs.com/lichen782/p/leetcode_maximal_rectangle.html一样!!
后来优化一下,不用stack了,用一个数组自己模拟栈,就过了。

public class Solution {
    public int maximalRectangle(char[][] matrix) {
        int m = matrix.length;
        if (m == 0) return 0;
        int n = matrix[0].length;
        if (n == 0) return 0;
        int h[][] = new int[m][n+1]; // n+1 is for holder 0
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (matrix[i][j] == '0') {
                    h[i][j] = 0;
                } else if (i == 0) {
                    h[i][j] = 1;
                } else {
                    h[i][j] = h[i-1][j] + 1;
                }
            }
        }
        int max = 0;
        for (int i = 0; i < m; i++)
        {
            int tmp = maxArea(h[i]);
            if (tmp > max) max = tmp;
        }
        return max;
    }
    
    private int maxArea(int[] h)
    {
        int max = 0;
        int[] stack = new int[h.length];
        int idx = -1;       
        int i = 0;
        while (i < h.length)
        {
            if (idx == -1 || h[i] >= h[stack[idx]])
            {
                idx++;
                stack[idx] = i;
                i++;
            }
            else {
                int t = stack[idx];
                idx--;
                int tmp = h[t] * (idx == -1 ? i : (i - stack[idx] - 1));
                if (tmp > max) max = tmp;
            }
        }
        return max;
    }
}

问题是那个O(n)单调栈的算法很难想到,这样的话还有一个容易想到点的算法,复杂度是O(n^3)的,只是有些优化:http://blog.sina.com.cn/s/blog_411fed0c0100bw8m.html
就是按行扫计算出每个位置的高度,这时回退到问题Largest Rectangle in Histogram。然后对任何一个高度向左向右扫,得到该高度能到cover的最左和最右。优化在于利用已经计算过的左侧的l[j]计算新l[j]
一行一行的求,如果这行的第j个是1 , 这 h[j]++; 否则 h[j] = 0;
然后对求第一行到这行的最大全1矩阵。
例如这行的h值为 5 1 1 5 3 5 这最大全1矩阵的和应该为9。
求这个需要两个数组 l[], r[] 分别表示以h[j]为矩阵的高的左边界和右边界:

for(j = 0; j < m; j ++)
{
  l[j] = j;
  while(l[j] > 0 && h[j] <= h[l[j] - 1])
  l[j] = l[l[j] - 1];
}

5 的左边界为 0。1 的左边界为1< 5, 1 的左边界肯定在5的左边界的左边 l[j] = l[l[j]–1]

扩展阅读:http://community.topcoder.com/stat?c=problem_statement&pm=13035

原文地址:https://www.cnblogs.com/lautsie/p/3286271.html