LeetCode 85. 最大矩形(枚举+前缀和、预处理+单调栈、DP+单调栈)

最大矩形

  • 枚举+前缀和
    关键是如何枚举出所有可能的矩形,并且尽可能高效。
    对于每个矩形而言,用四个变量可以去唯一确定。i,j,k,now,含义分别是,这个矩形头部的列序号、尾部的列序号、头部的行号、一共多少行。
    其中 i , j i , j 直接两层for循环即可,对于k、now,可以这样处理,从第一行一直遍历到最后一行,记录下能够构成矩形的一行的行的个数,然后用它去更新答案。
    为了快速判定某一行的某一段是不是全都是1,可以记录一下每一行的前缀和。
    时间复杂度: O ( n 2 m ) O(n^2*m)
class Solution {
public:
    int maximalRectangle(vector<vector<char>>& a) {
        if(a.size()==0 || a[0].size()==0) return 0;
        int ans = 0 ;
        int m = a.size() , n = a[0].size();
        vector<vector<int>> s(m,vector<int>(n));
        for(int i=0;i<m;i++) {
            s[i][0] = a[i][0]-'0';
            for(int j=1;j<n;j++){
                s[i][j] = s[i][j-1] + a[i][j]-'0';
            }
        }
        for(int l=0;l<n;l++){
            for(int r=l;r<n;r++){
                int now = 0;
                for(int k=0;k<m;k++){
                    int ss = s[k][r];
                    if(l>0){
                        ss -= s[k][l-1];
                    }
                    if( ss == r-l+1 ){
                        now++;
                    }else{
                        ans = max(ans,(r-l+1)*now);
                        now = 0;
                    }
                }
                if(now){
                    ans = max(ans,(r-l+1)*now); // 不要忘记
                }
            }
        }
        return ans;
    }
};
  • 单调栈
    思路:
    把矩阵的每一行作为84题那样的矩形的最底层,然后依次处理即可。
    (图片来自力扣)
    在这里插入图片描述
    理解这张图、然后预处理一下矩阵。
    时间复杂度: O ( m n ) O(m*n)

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& a) {
        if(a.size()==0 || a[0].size()==0) return 0;
        int ans = 0 ;
        int m = a.size() , n = a[0].size();
        vector<vector<int>> dp(m,vector<int>(n,0));
       // 从这一行的这一列开始,往上连续的最多有多少个1.
        for(int j=0;j<n;j++){
            if(a[0][j]=='1') dp[0][j] = 1;
        }
        for(int i=1;i<m;i++){
            for(int j=0;j<n;j++){
                if(a[i][j]=='1'){
                    dp[i][j] = dp[i-1][j] + 1;
                }else{
                    dp[i][j] = 0;
                }
            }
        }
        for(int i=0;i<m;i++){
            ans = max(ans,largestRectangleArea(dp[i]));
        }
        return ans;
    }
    // LeetCode 84 题的代码,完全可以直接拿来使用
    int largestRectangleArea(vector<int>& a) {
        typedef pair<int,int> P;
        int ans = 0;
        stack<P> s;
        for(int x:a){
            if(s.empty() || s.top().first<=x){
                s.push(make_pair(x,1));
            }else{
                int width = 0;
                while(!s.empty() && s.top().first>x){
                    P p = s.top();
                    s.pop();
                    width += p.second;
                    ans = max(ans,width*p.first);
                }
                s.push(make_pair(x,width+1));
            }
        }
        int width = 0;
        while(!s.empty()){
            P p = s.top();
            s.pop();
            width += p.second;
            ans = max(ans,width*p.first);
        }
        return ans;
    }    
};

  • 下面参考一位网友的写法、换了一种写法去枚举矩形,不过时间复杂度仍为:
    O ( n 2 m ) O(n^2*m)
    思考一下,这种写法是怎么优化到上面的 O ( m n ) O(m*n) 的,这种做法是枚举每一个矩形的右下角,然后去维护一个单调的轮廓(正是单调栈的思想)。
    但是冗余的操作呢?很明显: d p [ i 1 ] [ j ] [ 2 ] d p [ i ] [ j ] [ 2 ] dp[i-1][j][2]、dp[i][j][2] 其实有太多重复的计算过程。
    于是最终可以一行一行的去就算,而不是一个一个地去计算。
    在这里插入图片描述
class Solution {
public:
    int maximalRectangle(vector<vector<char>>& a) {
        if(a.size()==0 || a[0].size()==0){
            return 0;
        }
        int m = a.size(), n = a[0].size(), ans = 0;
        vector<vector<vector<int>>> dp(m+1,vector<vector<int>>(n+1,vector<int>(2,0)));
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(a[i-1][j-1]=='1'){
                    dp[i][j][0] = dp[i][j-1][0] + 1; //向左连续的1的个数
                    dp[i][j][1] = dp[i-1][j][1] + 1; //向上连续的1的个数
                    int res = 0;
                    int ls = dp[i][j][0];
                    int rows = dp[i][j][1];
                    for(int k=0;k<rows;k++){
                        ls = min(ls,dp[i-k][j][0]);
                        ans = max(ans,ls*(k+1));
                    }
                    ans = max(ans,res);   
                }
            }
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/107504273