85. Maximal Rectangle (Hard)

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.

此题是之前那道的 Largest Rectangle in Histogram 直方图中最大的矩形 的扩展,这道题的二维矩阵每一层向上都可以看做一个直方图,输入矩阵有多少行,就可以形成多少个直方图,对每个直方图都调用 Largest Rectangle in Histogram 直方图中最大的矩形 中的方法,就可以得到最大的矩形面积。那么这道题唯一要做的就是将每一层构成直方图,由于题目限定了输入矩阵的字符只有 '0' 和 '1' 两种,所以处理起来也相对简单。方法是,对于每一个点,如果是‘0’,则赋0,如果是 ‘1’,就赋 之前的height值加上1。具体参见代码如下:

Solution 1: stack

int maximalRectangle(vector<vector<char>>& matrix) {
    int area = 0;
    int n = matrix.size();
    if (n == 0) return 0;
    int m = matrix[0].size();
    vector<int> v(m, 0);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            v[j] = matrix[i][j] == '0' ? 0:1+v[j];
        }
        area = max(area, largestRectangleArea(v));
    }
    return area;
}

int largestRectangleArea(vector<int>& heights) {
    heights.push_back(0); // ensure all heights stored in s are checked
    int area = 0, n = heights.size(), end = -1;
    vector<int> s(n);
    for (int i = 0; i < n; ++i) {
        while (end != -1 && heights[s[end]] >= heights[i]) {
            int top = heights[s[end]]; --end;
            // area between i and second tallest height in stack 
            // (excluding)
            area = max(area, top*(end == -1 ? i:i-s[end]-1));
        }
        s[++end] = i;
    }
    return area;
}

combine two functions

int maximalRectangle(vector<vector<char>>& matrix) {
    int area = 0, n = matrix.size();
    if (n == 0) return 0;
    // add one more 0 at the end
    // ensure all heights stored in s are checked
    int m = matrix[0].size()+1; 
    vector<int> heights(m, 0), s(m);

    for (int i = 0; i < n; ++i) {
        int end = -1;
        for (int j = 0; j < m; ++j) {
            if (j < m-1)
                heights[j] = matrix[i][j] == '0' ? 0:1+heights[j];

            while (end != -1 && heights[s[end]] >= heights[j]) {
                int top = heights[s[end]]; --end;
                area = max(area, top*(end == -1 ? j:j-s[end]-1));
            }
            s[++end] = j;
        }
    }
    return area;
}

Solution 2: dp

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'

If you think this algorithm is not easy to understand, you can try this example:

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

The vector "left" and "right" from row 0 to row 2 are as follows

row 0:

l: 0 0 0 3 0 0 0
r: 7 7 7 4 7 7 7

row 1:

l: 0 0 2 3 2 0 0
r: 7 7 5 4 5 7 7

row 2:

l: 0 1 2 3 2 1 0
r: 7 6 5 4 5 6 7
int maximalRectangle(vector<vector<char>>& matrix) {
    if (matrix.empty() || matrix[0].empty()) return 0;
    int res = 0, m = matrix.size(), n = matrix[0].size();
    vector<int> height(n, 0), left(n, 0), right(n, n);
    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') ++height[j];
            else height[j] = 0;
        }
        for (int j = 0; j < n; ++j) {
            if (matrix[i][j] == '1') left[j] = max(left[j], cur_left);
            else {left[j] = 0; cur_left = j + 1;}
        }
        for (int j = n - 1; j >= 0; --j) {
            if (matrix[i][j] == '1') right[j] = min(right[j], cur_right);
            else {right[j] = n; cur_right = j;}
        }
        for (int j = 0; j < n; ++j) {
            res = max(res, (right[j] - left[j]) * height[j]);
        }
    }
    return res;
}

Combine some for loops

int maximalRectangle(vector<vector<char>>& matrix) {

    int n = matrix.size();
    if (n == 0) return 0;
    int m = matrix[0].size(), area = 0;

    vector<int> left(m,0), right(m,m), heights(m,0);
    for (int i = 0; i < n; ++i) {
        int cur_left = 0, cur_right = m;
        // height :
        // left boundary : from left to right
        for (int j = 0; j < m; ++j) {
            if (matrix[i][j] == '1') {
                ++heights[j];
                left[j] = max(left[j], cur_left);
            } else {
                heights[j]=0;
                left[j] = 0;
                cur_left = j+1;
            }
        }

        for (int j = m-1; j >= 0; --j) {
            if (matrix[i][j] == '1') right[j] = min(right[j], cur_right);
            else { right[j] = m; cur_right = j; }
            area = max(area, (right[j]-left[j])*heights[j]);
        }

    }
    return area;
}

results matching ""

    No results matching ""