矩形区域不超过K的最大数值和
题目出处:https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/
问题的转换:
- 二维问题转换成一维问题:枚举区域中矩形的上下边界,在当前以i为上边界,j为下边界的矩形中,对每一列求和,放入SumCol中。此时问题就转换为“在一维数组nums中,找出某个最大区间和,满足Sr-Sl <= k”,其中Si=nums0+nums1+…+sumi。因此还需对得到的一维数组计算每个位置的前缀和,放入数组PreSum中。
- 遍历一维数组PreSum。从左到右遍历,将遍历过的元素放入一个有序集合中(当前元素之前的所有元素都在该有序集合中),当遍历到PreSum[r]时,就在这个集合中查找是否存在一个元素PreSum[l]使得PreSum[l]>=PreSum[r]-k,求出PreSum[l]的最小值t,若存在该最小值t,则更新ans=min(ans, PreSum[r]-t),将当前元素PreSum[r]放入集合中;不若存在最小值t,也将当前元素PreSum[r]放入集合中,则继续遍历PreSum。
class Solution {
public:
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
int ans = INT_MIN;
int m = matrix.size(), n = matrix[0].size();
for(int i = 0; i < m; ++i){ //枚举矩形的上边界
vector<int> SumCol(n, 0);
for(int j = i; j < m; ++j){ //枚举矩形的下边界
for(int c = 0; c < n; ++c){ //统计每一列的元素和,放入SumCol中
SumCol[c] += matrix[j][c];
}
set<int> st{0};
int SUM = 0;
//vector<int> PreSum(n, 0); //定义前缀和,枚举r
for(int v : SumCol){
SUM += v;
//PreSum[i] = SUM;
auto lb = st.lower_bound(SUM-k);
if(lb != st.end()){
ans = max(ans, SUM-*lb);
}
st.insert(SUM);
}
}
}
return ans;
}
};