【矩阵二维或三维dp】最大子矩阵,子矩阵快速求和(用到最大直方图)

Maximal Rectangle

  Total Accepted: 9039  Total Submissions: 41503 My Submissions

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.

三种递推方法:

1 maxR[i][j]=max{  minHCnt(k...j)*(j+1-k)  }, k=0...j 注意剪枝。当hCnt[k-x]>hCnt[k]时就可以删掉hCnt[k].可以用线性扫描方法一遍剪枝 (112ms)

2 maxR[i][k][j]=maxR[i-1][k][j]+(j+1-k), 其中arr[i][k~j]都必须是‘1'。否则maxR[i][k][j]=0.(72ms)

3 maxR[i][j] = maxHistogram{ maxHCntOne[k...i][j] }, 其中maxHCntOne和maxHistogram是O(n)的,整个算法是O(n^n)的

方法1:

注意 list 反向 loop 并删除 的写法!

class Solution {
public:
#define MAXN 200000
    //线性扫描+3维dp
    int maximalRectangle(vector > &matrix) {
        int n=matrix.size();if(n==0) return 0;
        int m=matrix[0].size();if(m==0) return 0;
        vector > hCnt(n,vector(m,0));
        for(int j=0;j0?hCnt[i-1][j]+1:1;
                else hCnt[i][j]=0;
            }
        }
        
        //find the largest rect from hCnt[i][j]
        int mR=0;
        typedef pair Pr;
        for(int i=0;i tmp;
            for(int j=0;jhCnt[i][j+1]||j==0||hCnt[i][j]>hCnt[i][j-1]) //h[i][j] is not a extremal small value @@@error:j==0 fault as i==0
                    tmp.insert(tmp.begin(),Pr(j,hCnt[i][j]));
                if(tmp.empty()) continue;///@@@error: must consider list empty, then the for loop will not work
                for(list::iterator k=(--tmp.end());;k--){
                    int t=min(hCnt[i][j],k->second);
                    if(t>mH){
                        k->second= mH=t;
                        mR=max(mR,mH*(j-k->first+1));
                    }
                    else {//erase
                        tmp.erase(k++);//@@warning:after erase, k point to next node (or end())
                    }
                    //after handling the last element(tmp.begin()),break
                    if(k==tmp.begin()) break;
                }
            }
        }
        return mR;
    }
};

方法2:

class Solution {
public:
    int maximalRectangle(vector > &matrix) {
        int L=matrix.size();
        if(L<=0) return 0;
        int R=matrix[0].size();
        int R2=R*R;
        int *height=new int [R*R*2];
        memset(height,0,sizeof(int)*2*R*R);
        int max=0;
        for(int i=0;i
方法3:
class Solution {
public:
    int maximalRectangle(vector > &matrix) {
        int n = matrix.size();
        if(!n) return 0;
        int m = matrix[0].size();
        if(!m) return 0;
        
        vector > lines(n, vector(m, 0));
        int maxArea = 0;
        
        for(int i = 0; i0? lines[i-1][j]:0; //@error: j>0? lines[i][j-1]
                if(matrix[i][j]=='1') lines[i][j] = t+1;
                else lines[i][j] = 0;
            }
            
            // max rectangle in lines[i][0, m-1]
            stack > ss;
            int tmp = 0;
            for(int j = 0; j<=m; j++){
                int t = j==m? -1 : lines[i][j], s = 0;
                while(!ss.empty() && ss.top().first>= t){
                    s+= ss.top().second;
                    tmp = max(tmp, ss.top().first*s);
                    ss.pop();
                }
                ss.push(pair(t, s+1));
                tmp = max(tmp, t*(s+1));
            }
            
            maxArea = max(maxArea, tmp);
        }
        
        return maxArea;
    }
};

子矩阵求和

一个矩阵A[m][n]子矩阵之和快速求法(包含更新A[x][y]和查询 Sum(i1, j1, i2, j2))
1  B[I][J] 表示 子矩阵:A[0][0] 到 A[I][J]  的和。 则Sum(i1, j1, i2, j2) = B[i2][j2] - B[i2][j1] - B[i1][j2] + B[i1][j1], 
查询复杂度O(1), 
更新复杂度: 当A[x][y]变化时,B[x, m-1][y, n-1]都需要更新,复杂度 O(n^2)
2 B[I][J]表示行B[I][0]到B[I][J]的和, 那么 则Sum(i1, j1, i2, j2) = E(B[i1,i2][j2] - B[i1,i2][j1] )
查询复杂度O(n)
更新复杂度O(n)
3 上述变形,B[I]变成一颗线段树,维护该行的区间和。
则Sum(B[I][ j1<= j <= j2) 可以变成B[I]这棵线段树的区间求和(O(lgn) ),记为T[I].  
那么 Sum(i1, j1, i2, j2) = E(T[i1, i2])(O(n*lgn) )
查询复杂度O(nlgn)
更新复杂度O(1)
4 上述变形, B[I]变成一颗线段树,维护C[I][j] (= sum(A[0, I][j]) )的区间和。
令T[I] = B[I][ j1, j2 ](O(lgn)), 
Sum(i1, j1, i2, j2) =T[i2] - T[i1]   (O(lgn))
查询复杂度 O(lgn)
更新复杂度:当A[x][y]变化时,需要更新C[x, m-1][y], 复杂度 O(n)

你可能感兴趣的:(leetcode,线性扫描,dp,矩阵)