[leetcode] 221. Maximal Square && 85. Maximal Rectangle

Maximal Square

Given a 2D binary matrix filled with 0’s and 1’s, find the largest square containing only 1’s and return its area.
Example:

Input:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Output: 4

解法

动态规划,找到每一个位置的可以达到的最大的正方形的边长。

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int> > dp(m, vector<int> (n, 0));
        int res = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i == 0 || j == 0)
                    dp[i][j] = matrix[i][j] == '1' ? 1:0;
                else{
                    if(matrix[i][j] == '1')
                        dp[i][j] = min(dp[i][j-1],min(dp[i-1][j],dp[i-1][j-1])) + 1;
                    else
                        dp[i][j] = 0;
                }
                res = max(res, dp[i][j]);
            }
        }
        return res*res;
    }
};

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.
Example:

Input:
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
Output: 6

直方图中最大的面积

可以把这个问题变成求直方图中最大的矩形面积;
对矩阵的每一行加上这行之前的所有行构成一个直方图heights,如果当前值为1,则heights[j]++,否则为0
对每一个直方图进行求最大面积值,最后得到的所有直方图的最大面积就是结果。

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> heights(n, 0);
        int res = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(matrix[i][j] == '1')
                    heights[j] ++;
                else
                    heights[j]= 0;  
            }
            res = max(res,LargeRecinHisto(heights));
        }
        return res;
    }
    
    int LargeRecinHisto(vector<int> heights){
        stack<int> s;
        heights.push_back(0);
        int max_value = 0;
        for(int i=0;i<heights.size();i++){
            if(s.empty() || heights[i] >= heights[s.top()])
                s.push(i);
            else{
                while(!s.empty() && heights[i] < heights[s.top()]){
                    int cur = s.top(); 
                    s.pop();
                    max_value = max(max_value, heights[cur]*(s.empty() ? i : i-s.top()-1));
                }
                s.push(i);
            }   
        }
        return max_value;
    }
};

一个函数解决

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> heights(n+1, 0);
        int res = 0;
        for(int i=0;i<m;i++){
            stack<int> s;
            for(int j=0;j<n+1;j++){
                if(j<n)
                    heights[j] = matrix[i][j] == '1' ? heights[j]+1:0;
                while(!s.empty() && heights[j] <= heights[s.top()]){
                    int cur = s.top(); 
                    s.pop();
                    res = max(res, heights[cur]*(s.empty() ? j : j-s.top()-1));
                }
                s.push(j);
            }
        }
        return res;
    }
};

解法2

构造一个heights数组和解法1相同,然后再构造一个left和right数组
left数组表示:如果当前值matrix[i][j]==1,left[j]为与其相连都为1的左边界位置,否则为0;
right数组表示:如果当前值matrix[i][j]==1,right[j]为与其相连都为1的右边界位置+1,否则为n;
对于任意一个位置的[i][j],面积表示为(right[j]-left[j])*heights[j]。
举个栗子:

[
[1, 1, 0, 0, 1],
[0, 1, 0, 0, 1],
[0, 0, 1, 1, 1],
[0, 0, 1, 1, 1],
[0, 0, 0, 0, 1]
]

第0行:

h: 1 1 0 0 1
l: 0 0 0 0 4
r: 2 2 5 5 5

第1行:

h: 0 2 0 0 2
l: 0 1 0 0 4
r: 5 2 5 5 5

第2行:

h: 0 0 1 1 3
l: 0 0 2 2 4
r: 5 5 5 5 5

第3行:

h: 0 0 2 2 4
l: 0 0 2 2 4
r: 5 5 5 5 5

第4行:

h: 0 0 0 0 5
l: 0 0 0 0 4
r: 5 5 5 5 5

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> heights(n, 0), left(n, 0), right(n, n);
        int res = 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'){
                    heights[j]++;
                    left[j] = max(left[j], cur_left);
                }
                else{
                    heights[j] = 0;
                    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;
                }
                res = max(res, (right[j] - left[j]) * heights[j]);
            }
        }
        return res;
    }
};

解法3

先统计每一行的连续1的个数,使用一个数组 h_max, 其中 h_max[i][j] 表示第i行,第j个位置水平方向连续1的个数,若 matrix[i][j] 为0,那对应的 h_max[i][j] 也一定为0;
再次遍历每个位置,首先每个位置的 h_max 值都先用来更新结果 res,因为高度为1也可以看作是矩形,然后我们向上方遍历,上方 (i, j-1) 位置也会有 h_max 值,但是用二者之间的较小值才能构成矩形,用新的矩形面积来更新结果 res,这样一直向上遍历,直到遇到0,或者是越界的时候停止,这样就可以找出所有的矩形了。

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.empty() || matrix[0].empty())
            return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int> > h_max(m, vector<int> (n,0));
        int res = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if (matrix[i][j] == '0') continue;
                if (j > 0) h_max[i][j] = h_max[i][j - 1] + 1;
                else h_max[i][0] = 1;
            }
        }
        for(int i=0;i<m;i++){
            for (int j = 0; j < n; ++j) {
                if (h_max[i][j] == 0) continue;
                int mn = h_max[i][j];
                res = max(res, mn);
                for (int k = i - 1; k >= 0 && h_max[k][j] != 0; --k) {
                    mn = min(mn, h_max[k][j]);
                    res = max(res, mn * (i - k + 1));
                }
            }
        }
        return res;
    }
};

参考

https://www.cnblogs.com/grandyang/p/4322667.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值