我的leetcode之旅--矩形区域不超过k的最大数值和

版权声明: https://blog.csdn.net/gjwStronger/article/details/88075812

矩形区域不超过k的最大数值和(2019.03.02)

题目描述

给定一个非空二维矩阵 matrix 和一个整数 k,找到这个矩阵内部不大于 k 的最大矩形和。

示例:
输入: matrix = [[1,0,1],[0,-2,3]], k = 2
输出: 2 
解释: 矩形区域 [[0, 1], [-2, 3]] 的数值和是 2,且 2 是不超过 k 的最大数字(k = 2)。

说明:
矩阵内的矩形区域面积必须大于 0。
如果行数远大于列数,你将如何解答呢?

解法分析

看到这道题的难度是困难,就预感到做不出来了。但是一看官方还没出题解,想着就算硬着头皮,使用暴力求解总会有个结果。最简单的暴力求解法是遍历大矩阵中的所有子矩阵,再对子矩阵进行循环求和,得到想要的结果。粗略一算会嵌套六层循环,代价很大,时间复杂度为 O ( n 6 ) O(n^6) 。最后试了一下:

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        int row=matrix.size();
        int col=matrix[0].size();    
        int maxsum;
        int flag=0;
        for(int i=0;i<row;++i)
            for(int j=0;j<col;++j)
                for(int deltaRow=1;i+deltaRow-1<row;++deltaRow)
                    for(int deltaCol=1;j+deltaCol-1<col;++deltaCol){
                        int sum=0;
                        for(int m=i;m<=i+deltaRow-1;++m)
                            for(int n=j;n<=j+deltaCol-1;++n){
                                sum+=matrix[m][n];
                            }
                        if(sum<=k){
                            if(flag==0)
                            {   
                                maxsum=sum;
                                flag=1;
                            }
                            else{
                                maxsum=(maxsum>=sum)?maxsum:sum;    
                                if(maxsum==k)
                                   return maxsum;
                            }
                        }                          
                    }
        return maxsum;            
        }
    
};

提交后会因为运行超出时间限制而失败。看来必须对算法进行优化。
查阅资料后得知,可使用积分图的方法对子矩阵求和的过程进行简化,避免重复计算。所谓积分图,就是矩阵上每个元素的值都等于该元素右上角所有元素的和。在这里插入图片描述
这样,计算任意一个子矩阵的数值和的公式在积分图上就可以表示为:
( u v   x y ) = ( 00   x y ) ( 00   x v ) ( 00   u y ) + ( 00   u v ) 子矩阵(uv~xy)数值和=子矩阵(00~xy)数值和-子矩阵(00~xv)数值和-子矩阵(00~uy)数值和+子矩阵(00~uv)数值和
个人觉得这算是一种动态规划(DP)的方法,简化了子矩阵求和的过程,但是依然需要遍历所有子矩阵。时间复杂度 O ( n 2 ) + O ( n 4 ) O(n^2)+O(n^4)

  class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int>> dp(m, vector<int>(n, 0));
        dp[0][0] = matrix[0][0];
        for (int i = 1; i<m; ++i) {
            dp[i][0] = dp[i - 1][0] + matrix[i][0];
        }
        for (int i = 1; i<n; ++i) {
            dp[0][i] = dp[0][i - 1] + matrix[0][i];
        }
        for (int i = 1; i<m; ++i) {
            for (int j = 1; j<n; ++j) {
                dp[i][j] = matrix[i][j]+dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];
            }
        }
        int maxArea = INT_MIN;
        for (int a = 0; a<m; ++a) {
            for (int b = a; b<m; ++b) {
                for (int c = 0; c<n; ++c) {
                    for (int d = c; d<n; ++d) {
                        int topArea = a == 0 ? 0 : dp[a - 1][d];
                        int leftArea = c == 0 ? 0 : dp[b][c - 1];
                        int ltArea = (a == 0 || c == 0) ? 0 : dp[a - 1][c - 1];
                        int curSum = dp[b][d] - leftArea - topArea + ltArea;
                        if (curSum == k)
                            return k;
                        if (curSum<k)
                            maxArea = max(maxArea, curSum);
                    }
                }
            }
        }
        return maxArea;
    }
};
执行用时: 3896 ms, 在Max Sum of Rectangle No Larger Than K的C++提交中击败了0.00% 的用户
内存消耗: 10.5 MB, 在Max Sum of Rectangle No Larger Than K的C++提交中击败了0.00% 的用户

发现还有避免暴力遍历子矩阵的方法,进一步减少运行时间,日后补充。

猜你喜欢

转载自blog.csdn.net/gjwStronger/article/details/88075812