第一题:560. 和为 K 的子数组 - 力扣(LeetCode)
为什么不能用滑动窗口?举个例子:nums=[1,2,3,-2] ,k=4.left为1,right为3时,发现窗口内的值已经比4要大,所以left右移。但漏掉了1+2+3+(-2)=4这一组。因为负值的存在,无法判断究竟是要扩大窗口,还是滑动到下一个窗口。
考虑用前缀和。对于一个起始位置为j,终止位置为i的子串,其元素和为pre[i]-pre[j-1].如果pre[i]-pre[j-1]==k,那么这个子串是符合题意的。移项可得:pre[j-1]=pre[i]-k.我们遍历一次nums可以得到每个位置的前缀和,那么不妨在得到pre[i]的同时,看是否存在前缀和为pre[i]-k的子串,如果存在就将答案增加相应的个数.考虑用unordered_map,因为我们要找“是否存在前缀和为pre[i]-k的子串”,所以key为前缀和,value为这样的子串的个数。
需要注意的是mp[0]=1,因为如果pre恰好为k,那么pre-k=0,这样的子串是存在的。
class Solution
{
public:
int subarraySum(vector<int>& nums, int k)
{
unordered_map<int, int>mp;//键:前缀和,值:出现次数
int pre = 0, cnt = 0;
mp[0] = 1;
for (int x : nums)
{
pre += x;
if (mp.contains(pre - k))
{
cnt += mp[pre - k];
}
mp[pre]++;
}
return cnt;
}
};