https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/
思路:考虑枚举左右边界
l
、
r
l、r
l、r,计算该区间内每一行元素的和,可以得到一个数组
s
u
m
sum
sum,如果可以找到两个位置
i
、
j
i、j
i、j满足
∑
k
=
i
j
s
u
m
k
=
t
a
r
g
e
t
\sum_{k=i}^{j}sum_k=target
∑k=ijsumk=target,那么就找到了一组可行解,其左上角坐标为
(
l
,
i
)
(l,i)
(l,i),右下角坐标为
(
r
,
j
)
(r,j)
(r,j)。但是如果还是暴力枚举
i
、
j
i、j
i、j判断的话,算法复杂度是
O
(
n
2
m
2
)
O(n^2m^2)
O(n2m2),怎么降低复杂度呢?
现在来考虑子问题:在数组 s u m sum sum中找到和为 t a r g e t target target的子区间个数。首先考虑暴力做法,我们可以先处理出 s u m sum sum数组的前缀和数组,设其为 t o t a l total total,然后限定区间右边界 r r r,再枚举区间左边界 l l l,判断 t o t a l r − t o t a l l − 1 total_r-total_{l-1} totalr−totall−1是否等于 t a r g e t target target。因为 t o t a l r 、 t a r g e t total_r、target totalr、target其实都是固定不变的,因此实际上我们是在求解在 t o t a l total total数组的区间 [ 0 , r ] [0,r] [0,r]内等于 t o t a l r − t a r g e t total_r-target totalr−target的元素个数。那么可以用哈希表来记录,省去枚举的操作,降低时间复杂度。
class Solution {
public:
int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
int m=matrix.size(),n=matrix[0].size(),ans=0;
// 枚举左边界
for(int l=0;l<n;l++)
{
vector<int> sum(m);
// 枚举右边界
for(int r=l;r<n;r++)
{
// 更新每一行的和
for(int i=0;i<m;i++)
sum[i]+=matrix[i][r];
ans+=cal(sum,target);
}
}
return ans;
}
int cal(const vector<int>& sum,int target)
{
int m=sum.size(),total=0,ans=0;
unordered_map<int,int> cnt;
cnt[0]=1;
for(int i=0;i<m;i++)
{
total+=sum[i];
auto it=cnt.find(total-target);
if(it!=cnt.end())
ans+=it->second;
++cnt[total];
}
return ans;
}
};