问题:
给定二维数组,
求其中子矩形中元素和不大于K 的最大和。
Example 1: Input: matrix = [[1,0,1],[0,-2,3]], k = 2 Output: 2 Explanation: Because the sum of the blue rectangle [[0, 1], [-2, 3]] is 2, and 2 is the max number no larger than k (k = 2). Example 2: Input: matrix = [[2,2,-1]], k = 3 Output: 3 Constraints: m == matrix.length n == matrix[i].length 1 <= m, n <= 100 -100 <= matrix[i][j] <= 100 -10^5 <= k <= 10^5
example 1:
解法:preSum(前缀和)
以往我们使用preSum方法,都是在一维数组中。
而这次需要在二维数组中使用,则需要进行降维。
固定列的范围:lj~rj (外层再进行遍历所有范围可能)
对于任意行 i:将多列压缩成一列->preColSum[i]
这样,我们得到多行的列压缩结果。
这样,就成了一维。{0,2,6,-8,4,6}
对这个一维数组,进行前缀和求解即可。
求任意区间的和<=K, 中求最大和。
这里,我们使用二分查找,进行快速查找。
利用辅助前缀和set:preSum
来保存已经遍历过的前缀和。
那么要求的,即为前缀和preSum中 >=当前前缀和curSum-K
这里,由于set是排序set,使用lower_bound即可找到第一个>=curSum-K的数x
即 K>=curSum-x
再将当前前缀和curSum加入已遍历前缀和set:preSum。
代码参考:
1 class Solution { 2 public: 3 int maxSumSubmatrix(vector<vector<int>>& matrix, int k) { 4 int res=INT_MIN; 5 int n = matrix.size(), m = matrix[0].size(); 6 for(int lj=0; lj<m; lj++) { 7 vector<int> preColSums(n,0);//->==rows |<- 8 //combine left:<- col[lj ~ rj] 9 for(int rj=lj; rj<m; rj++) { 10 //in one row, width=[lj, rj] 11 for(int i=0; i<n; i++) { 12 preColSums[i] += matrix[i][rj]; 13 } 14 set<int> preSum={0};//preSum need a 0 as minus data 15 int curSum=0; 16 //combine up ↑ 17 for(int i=0; i<n; i++) { 18 curSum+=preColSums[i]; 19 auto it = preSum.lower_bound(curSum-k); 20 if(it!=preSum.end()) res=max(res, curSum-*it); 21 preSum.insert(curSum); 22 } 23 } 24 } 25 return res; 26 } 27 };