思路: 一种naive的算法就是枚举每个矩形块, 时间复杂度为O((mn)^2), 可以做少许优化时间复杂度可以降低到O(mnnlogm), 其中m为行数, n为列数.
先求出任意两列之间的所有数的和, 然后再枚举任意两行之间的和, 而我们优化的地方就在后者. 我们用s[x]来表示第x行从a列到b列的和. 遍历一遍从第0行到最后一行的求和数组, 并依次将其放到二叉搜索树中, 这样当我们知道了从第0行到当前行的和的值之后, 我们就可以用lower_bound在O(log n)的时间复杂度内找到能够使得从之前某行到当前行的矩阵值最接近k. 也就是说求在之前的求和数组中找到第一个位置使得大于(curSum - k), 这种做法的原理是在curSum之下规定了一个bottom-line, 在这上面的第一个和就是(curSum-val)差值与k最接近的数. 还需要注意的是预先为二叉搜索树加一个0值, 这种做法的原理是如果当前curSum小于k, 那么至少本身是一个潜在的解. 说的有点乱, 请见谅, 不懂的请提问!
class Solution { public: int maxSumSubmatrix(vector<vector<int>>& matrix, int k) { if(matrix.size()==0) return 0; int row = matrix.size(), col = matrix[0].size(); int ans =INT_MIN; for(int i = 0; i < col; i++) { vector<int> sum(row, 0); for(int j =i; j < col; j++) { set<int> st{0}; int curSum =0, curMax = INT_MIN; for(int x = 0; x < row; x++) { sum[x] += matrix[x][j]; curSum += sum[x]; auto it = st.lower_bound(curSum-k); if(it!=st.end()) curMax = max(curSum - *it, curMax); st.insert(curSum); } ans = max(curMax, ans); } } return ans; } };