LeetCode 363:Max Sum of Rectangle No Larger Than K

题目链接

链接:https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/description/

题解&代码

1、暴力枚举所有的情况,时间复杂度O(n2*m2),实际耗时759 ms

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k) {
        int n=matrix.size(),m=matrix[0].size();

        vector<vector<int> > sumv(n+1,vector<int>(m+1,0));
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                sumv[i][j]=matrix[i-1][j-1]+sumv[i-1][j]+sumv[i][j-1]-sumv[i-1][j-1];
            }
        }

        int ans=-INF;
        for(int i1=1;i1<=n;i1++){
            for(int j1=1;j1<=m;j1++){
                for(int i2=i1;i2<=n;i2++){
                    for(int j2=j1;j2<=m;j2++){
                        int val=sumv[i2][j2]-sumv[i1-1][j2]-sumv[i2][j1-1]+sumv[i1-1][j1-1];
                        if(val<=k){
                            ans=max(ans,val);
                        }
                    }
                }
            }
        }

        return ans;
    }
private:
    static const int INF=0x3f3f3f3f;
};

2、先通过枚举一维进行降维,然后再暴力枚举所有区间,时间复杂度O(m2*n2),实际耗时736ms。

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k) {
        int n=matrix.size(),m=matrix[0].size();

        vector<vector<int> > sumv(n+1,vector<int>(m+1,0));
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                sumv[i][j]=sumv[i][j-1]+matrix[i-1][j-1];
            }
        }

        int ans=-INF;
        vector<int> arr(n+1);
        for(int len=1; len<=m; len++) {
            for(int j=len; j<=m; j++) {
                arr[0]=0;
                for(int i=1; i<=n; i++) {
                    int val=sumv[i][j]-sumv[i][j-len];
                    arr[i]=val+arr[i-1];

                }
                for(int i=1;i<=n;i++){
                    for(int j=0;j<i;j++){
                        int x=arr[i]-arr[j];
                        if(x<=k) ans=max(ans,x);
                    }
                }

            }
        }
        return ans;
    }
private:
    static const int INF=0x3f3f3f3f;
};

3、 第2种方法基础上加一个剪枝,在枚举区间之前,先用dp(O(n))求出最大值区间和最小值区间,然后判断k是否在区间内,时间复杂度:‘玄学’,实际耗时19ms。

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k) {
        int n=matrix.size(),m=matrix[0].size();

        vector<vector<int> > sumv(n+1,vector<int>(m+1,0));
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                sumv[i][j]=sumv[i][j-1]+matrix[i-1][j-1];
            }
        }

        int ans=-inf;
        vector<int> arr(n+1);
        for(int len=1; len<=m; len++) {
            for(int j=len; j<=m; j++) {
                arr[0]=0;
                LL mi=inf,ma=-inf;
                LL pre=inf,aft=-inf;
                for(int i=1; i<=n; i++) {
                    int val=sumv[i][j]-sumv[i][j-len];
                    arr[i]=val+arr[i-1];
                    pre=min(pre+val,(LL)val);
                    aft=max(aft+val,(LL)val);
                    mi=min(mi,pre);
                    ma=max(ma,aft);
                }
                if(k<mi) continue;
                else if(k==mi) {
                    ans=k;
                } else if(k>=ma) {
                    ans=max((LL)ans,ma);
                } else {
                    for(int i=1; i<=n; i++) {
                        for(int j=0; j<i; j++) {
                            int x=arr[i]-arr[j];
                            if(x<=k) ans=max(ans,x);
                        }
                    }
                    if(ans==k) return ans;
                }

            }
        }
        return ans;
    }
private:
    static const int inf=0x7fffffff;
    typedef long long LL;
};

4、正解:先降维,然后枚举区间终点,用set维护前缀和,用lower_bound去查区间起点,从而O(nlogn)的复杂度解决该问题的一维版本。加上降维的时间复杂度为O(m^2*nlogn)。实际耗时:259ms。

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k) {
        int n=matrix.size(),m=matrix[0].size();

        vector<vector<int> > sumv(n+1,vector<int>(m+1,0));
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                sumv[i][j]=sumv[i][j-1]+matrix[i-1][j-1];
            }
        }

        int ans=-INF;
        vector<int> pre(n+1),arr(n+1);
        set<pair<int,int> > myset;
        set<pair<int,int> >::iterator it;
        for(int len=1; len<=m; len++) {
            for(int j=len; j<=m; j++) {
                pre[0]=0;
                myset.clear();
                for(int i=1; i<=n; i++) {
                    arr[i]=sumv[i][j]-sumv[i][j-len];
                    pre[i]=arr[i]+pre[i-1];
                    myset.insert(make_pair(pre[i],i));
                }
                for(int i=1;i<=n;i++){
                    if(arr[i]<=k) ans=max(ans,arr[i]);
                    int key=k-arr[i]+pre[i];
                    it=myset.lower_bound(make_pair(key,0x7fffffff));
                    if(it!=myset.begin()){
                        it--;
                        int tmp=it->first;
                        ans=max(ans,tmp-pre[i]+arr[i]);
                    }
                    myset.erase(make_pair(pre[i],i));
                }
            }
        }
        return ans;
    }
private:
    static const int INF=0x7fffffff;
};

5、正解优化版本(空间优化+常数优化)实际耗时:162ms。

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k) {
        int n=matrix.size(),m=matrix[0].size();
        int mi=min(n,m),ma=max(n,m);
        bool isColMax=m>n;
        int ans=-2147483648;
        for(int st=1; st<=mi; st++) {
            vector<int> arr(ma+1,0);
            for(int ed=st; ed<=mi; ed++) {
                set<int> myset;
                int cnt=0;
                myset.insert(cnt);
                for(int i=1; i<=ma; i++) {
                    arr[i]+=isColMax?matrix[ed-1][i-1]:matrix[i-1][ed-1];
                    cnt+=arr[i];
                    set<int>::iterator it=myset.lower_bound(cnt-k);
                    if(it!=myset.end()) ans=max(ans,cnt-*it);
                    myset.insert(cnt);
                }
            }
        }
        return ans;
    }
};

6、方法5+方法3提到的dp剪枝:实际耗时:19ms。

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k) {
        int n=matrix.size(),m=matrix[0].size();
        int mi=min(n,m),ma=max(n,m);
        bool isColMax=m>n;
        int ans=-2147483648;
        for(int st=1; st<=mi; st++) {
            vector<int> arr(ma+1,0);
            for(int ed=st; ed<=mi; ed++) {
                set<int> myset;
                int cnt=0;
                myset.insert(cnt);
                for(int i=1; i<=ma; i++) {
                    arr[i]+=isColMax?matrix[ed-1][i-1]:matrix[i-1][ed-1];
                    cnt+=arr[i];
                    set<int>::iterator it=myset.lower_bound(cnt-k);
                    if(it!=myset.end()) ans=max(ans,cnt-*it);
                    myset.insert(cnt);
                }
            }
        }
        return ans;
    }
};
posted @ 2017-08-03 11:50  fenicnn  阅读(147)  评论(0编辑  收藏  举报