题目描述
给你一个二元数组 nums ,和一个整数 goal ,请你统计并返回有多少个和为 goal 的 非空 子数组。子数组 是数组的一段连续部分。
示例 1:
输入:nums = [1,0,1,0,1], goal = 2
输出:4
解释:
如下面黑体所示,有 4 个满足题目要求的子数组:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
示例 2:
输入:nums = [0,0,0,0,0], goal = 0
输出:15
提示:
1 <= nums.length <= 3 * 104
nums[i] 不是 0 就是 1
0 <= goal <= nums.length
该题目可以使用前缀和来求解区间[l,r]的和,使用s[r]-s[l-1]得到,可以循环遍历两次,第一次遍历右端点,第二次遍历左端点,然后使用公式计算,但是两重循环会遇到一个数据出现超时,代码如下:
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
int n=nums.size();
vector<int> s(n+1,0);
for(int i=1;i<=n;i++) s[i]=s[i-1]+nums[i-1];
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
if(s[i]-s[j-1]==goal) res++;
}
}
return res;
}
};
因此使用哈希表存储前缀和,判断s[i]-goal 会不会出现在hash中,如果出现则表明有前缀和等于s[i]-goal,将其记录到结果中。
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
int n=nums.size();
unordered_map<int,int> hash;
vector<int> s(n+1,0);
for(int i=1;i<=n;i++) s[i]=s[i-1]+nums[i-1];
int res=0;
for(int i=1;i<=n;i++)
{
hash[s[i-1]]++;
res+=hash[s[i]-goal];
}
return res;
}
};
可以改进的地方是:前缀和也可以使用一个变量动态求解,不需要使用vector专门存储。
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
unordered_map<int,int> hash;
int sum=0,ans=0;
for(auto x:nums)
{
hash[sum]++;
sum+=x;
ans+=hash[sum-goal];
}
return ans;
}
};