[85] leetcode largest rectangle (dynamic programming, the stack)

Topic links: https://leetcode-cn.com/problems/maximal-rectangle/

Title Description

Given a two-dimensional binary matrix contains only 0 and 1, to find the largest rectangular contain only 1, and returns its area.

Example:

输入:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6

Here Insert Picture Description

Thinking

1 using an optimization method histogram of violence

Here Insert Picture Description
Setting two-dimensional array dp, dp[i][j]representing the maximum possible width of the rectangular coordinates of the end.

dp[i][j] = dp[i][j-1] + 1 if matrix[i][j] == '1'

Once we know the maximum width of each point corresponding to the maximum it can be calculated in the rectangle in the lower right corner point of the linear time. From this position we first iupward through the rows of the column, the maximum width may be obtained from the initial point (i, j) to the current point of the rectangle is the maximum width of each of the minimum we encountered d [k] [j] is.
We define

currentWidth = max(currentWidth, dp[i][k])
currentArea = currentWidth * (i - k + 1)
maxArea = max(maxArea, currentArea)

Repeat this process for each point, you can get the global maximum.
Note that we expect calculate the maximum width of the input method in fact transformed into a series of bar chart, each column is a new histogram. We calculate the maximum area for each histogram.

Here Insert Picture Description
Thus, the above-described method is essentially 84-- largest rectangle histogram optimization algorithm multiplexed force in question.

Complexity analysis
time complexity: O m 2 n O(m^2n)
spatial complexity: O m n O (mn)
m, n-number of the ranks of the input matrix

2 dynamic programming - the maximum height of each point

Imagine an algorithm for each point we will calculate a rectangle using the following steps:

不断向上方遍历,直到遇到“0”,以此找到矩形的最大高度。

向左右两边扩展,直到无法容纳矩形最大高度。

例如,找到黄色点对应的矩形:
Here Insert Picture Description

我们知道,最大矩形必为用这种方式构建的矩形之一。

给定一个最大矩形,其高为 h, 左边界 l,右边界 r,在矩形的底边,区间 [l, r]内必然存在一点,其上连续1的个数(高度)<=h。若该点存在,则由于边界内的高度必能容纳h,以上述方法定义的矩形会向上延伸到高度h,再左右扩展到边界 [l, r] ,于是该矩形就是最大矩形。

若不存在这样的点,则由于[l, r]内所有的高度均大于h,可以通过延伸高度来生成更大的矩形,因此该矩形不可能最大。

综上,对于每个点,只需要计算hl,和 r - 矩形的高,左边界和右边界。

使用动态规划,我们可以在线性时间内用上一行每个点的 hl,和 r 计算出下一行每个点的的hl,和r

算法

给定一行 matrix[i],我们通过定义三个数组heightleft,和 right来记录每个点的hl,和 rheight[j] 对应matrix[i][j]的高,以此类推。

问题转化为如何更新每个数组。

Height:

这个比较容易。 h 的定义是从该点出发连续的1的个数。

row[j] = row[j - 1] + 1 if row[j] == '1'

只需要一点改动即可:

new_height[j] = old_height[j] + 1 if row[j] == '1' else 0

Left:

考虑哪些因素会导致矩形左边界的改变。由于当前行之上的全部0已经考虑在当前版本的left中,唯一能影响left就是在当前行遇到0

因此我们可以定义:

new_left[j] = max(old_left[j], cur_left)
cur_left是我们遇到的最右边的0的序号加1。当我们将矩形向左 “扩展” ,我们知道,不能超过该点,否则会遇到0。

Right:

我们可以沿用 left 的思路,定义:

new_right[j] = min(old_right[j], cur_right)

cur_right 是我们遇到的最左边的0的序号。简便起见,我们不把 cur_right 减去1 (就像我们给cur_left加上1那样) ,这样我们就可以用height[j] * (right[j] - left[j]) 而非height[j] * (right[j] + 1 - left[j])来计算矩形面积。

这意味着, 严格地说 ,矩形的底边由半开半闭区间[l, r) 决定,而非闭区间 [l, r],且 right比右边界大1。尽管不这样做算法也可以正确运行,但这样会让计算看起来更简洁。

注意,为了正确的记录 cur_right,我们需要从右向左迭代。因此,更新right时需要从右向左。

一旦leftright,和 height数组能够正确更新,我们就只需要计算每个矩形的面积。

由于我们知道矩形 j的边界和高,可以简单地用height[j] * (right[j] - left[j])来计算面积,若j的面积 大于max_area,则更新之。

复杂度分析
时间复杂度: O m n O(mn)
spatial complexity: O n O (n)
m, n-number of the ranks of the input matrix

/*
 * 动态规划
 * 时间复杂度O(mn) 空间复杂度O(n)
 * m,n为数组行列数
 */
class SolutionII {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty()) return 0;
        int rows = matrix.size(), cols = matrix[0].size();
        vector<int> left(cols, 0);      // 最左边的1位置 左边界
        vector<int> right(cols, cols);  // 右边界
        vector<int> height(cols, 0);
        int maxArea = 0;
        for (int i = 0; i < rows; ++i) {
            int curLeft = 0;            // 遇到的最右边的0的序号加1
            int curRight = cols;        // 遇到的最左边的0的序号
            for (int j = 0; j < cols; ++j) {
                if(matrix[i][j] == '1')
                    height[j] += 1;
                else
                    height[j] = 0;
            }
            // 更新left
            for (int j = 0; j < cols; ++j) {
                if (matrix[i][j] == '1')
                    left[j] = max(left[j],curLeft);
                else{
                    left[j] = 0;
                    curLeft = j+ 1;
                }
            }
            // 更新right
            for (int j = cols-1; j >=0 ; --j) {
                if (matrix[i][j] == '1')
                    right[j] = min(right[j],curRight);
                else{
                    right[j] = cols;
                    curRight = j;
                }
            }
            // 更新最大面积
            for (int j = 0; j < cols; ++j) {
                maxArea = max(maxArea, height[j] * (right[j] - left[j]));
            }
        }
        return maxArea;
    }
};

Here Insert Picture Description

Guess you like

Origin blog.csdn.net/zjwreal/article/details/91468771