363.矩形区域不超过K的最大数值之和 1074.元素和为目标值的子矩阵数量
这两题放在一起是因为解题过程几乎一模一样:都是采用前缀和,先固定上下边界,求每一列之和,再求利用前缀和来求解。
1074:
class Solution {
public:
int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
int result(0);
//上边界
for(int i=0;i<matrix.size();++i)
{
//记录每一列元素之和
vector<int> sum(matrix[0].size());
//下边界
for(int j=i;j<matrix.size();++j)
{
//每一行
for(int k=0;k<matrix[0].size();++k)
{
sum[k]+=matrix[j][k];//单列单列的元素和
}
//[i,j]=k
//[0,j]-[0,i-1]=k
//[0,i-1]=[0,j]-k
//mp记录某一前缀和的个数
unordered_map<int,int> mp;
//防止无需减去某一前缀的情况
mp[0]=1;
int n(0);
for(int t=0;t<sum.size();++t)
{
//前t列的元素总和
n+=sum[t];
result+=mp[n-target];
++mp[n];
}
}
}
return result;
}
};
363
class Solution {
public:
int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
//与1074的解法类似噢
int result=INT_MIN;
for(int i=0;i<matrix.size();++i)
{
vector<int> sum(matrix[0].size());
for(int j=i;j<matrix.size();++j)
{
for(int s=0;s<matrix[0].size();++s)
{
sum[s]+=matrix[j][s];
}
//[i,j]<=k
//[0,j]-[0,i-1]<=k
//[0,i-1]>=[0,j]-k
set<int> save;
//防止出现前缀和就为为目标值的情况
save.insert(0);
int n(0);
for(int i=0;i<sum.size();++i)
{
n+=sum[i];
//二分查找找到与当前目标值相等或略大的数的下标
auto x=lower_bound(save.begin(),save.end(),n-k);
save.insert(n);
if(x==save.end()) continue;
result=max(result,n-*x);
}
}
}
return result;
}
};
区别:1076题是需要找到恰好等于目标值的区域个数,因此需要记录前缀的和以及个数;而363是需要找到一个最大的不大于目标值的区域和,因此不需要记录前缀和的个数,只需要记录有哪些前缀和,利用set可以自动给这些前缀和排序,再利用lower_bound函数(lower_bound(begin,end,target),其作用是二分查找到一个有序序列中不小于目标值的第一个数的迭代器)进行查找。
注意两题都需要加入0这个元素(mp[0]=1 or save,insert[0]),这是考虑了某一前缀和即为满足目标的情况
总结:前缀和的使用好灵活,leetcode好几道异或题也用到了前缀和。