现在的位置: 首页 > 综合 > 正文

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

2018年04月12日 ⁄ 综合 ⁄ 共 3273字 ⁄ 字号 评论关闭

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<vector<char> > &matrix) {
        int n=matrix.size();if(n==0) return 0;
        int m=matrix[0].size();if(m==0) return 0;
        vector<vector<int> > hCnt(n,vector<int>(m,0));
        for(int j=0;j<m;j++){
            int c=0;
            for(int i=0;i<n;i++){
                if(matrix[i][j]=='1') hCnt[i][j]=i>0?hCnt[i-1][j]+1:1;
                else hCnt[i][j]=0;
            }
        }
        
        //find the largest rect from hCnt[i][j]
        int mR=0;
        typedef pair<int,int> Pr;
        for(int i=0;i<n;i++){
            list<Pr> tmp;
            for(int j=0;j<m;j++){
                int mH=0;
                if(j==m-1||hCnt[i][j]>hCnt[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<Pr>::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<vector<char> > &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<L;i++){
            memset(height+(i%2)*R*R,0,sizeof(int)*R*R);//height[i%2][r][r]=0
            int c=i%2,d=(i+1)%2,tmp;
            for(int j=0;j<R;j++){
                for(int k=j;k<R;k++){
                    if(matrix[i][k]=='0') { break;}
                    else {
                        tmp=height[c*R2+j*R+k]=height[d*R2+j*R+k]+1;
                        max=max<tmp*(k-j+1)?tmp*(k-j+1): max;
                    }
                }
            }
        }
        return max;
    }
};

方法3:

class Solution {
public:
    int maximalRectangle(vector<vector<char> > &matrix) {
        int n = matrix.size();
        if(!n) return 0;
        int m = matrix[0].size();
        if(!m) return 0;
        
        vector<vector<int> > lines(n, vector<int>(m, 0));
        int maxArea = 0;
        
        for(int i = 0; i<n; i++){
            // lines[i][j]=maxCntOne(matrix[x, i][j])
            for(int j = 0; j<m; j++){
                int t = i>0? 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<pair<int, int> > 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<int, int>(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)

抱歉!评论已关闭.