解法一: 暴力计算 O(n^2)
使用前缀和
pre[i] = pre[i-1] + nums[i]
如果两个前缀和的差达到 k ,ans++
这个要想好一个问题, 就是包含首元素的和
计算包含首元素的和如 nums[0] nums[0]+nums[1] nums[0]+nums[1]+nums[2]
可以像我这样, 分开计算 也可以在sums中填充一个0,统一计算 .
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
vector<int> sums;
int count=0,sum=0;
for(int i=0;i<nums.size();i++){ //计算包含首元素的和如 nums[0] nums[0]+nums[1] nums[0]+nums[1]+nums[2]
sum+=nums[i];
if(sum==k) count++;
sums.push_back(sum);
}
for(int i=0;i<nums.size();i++){
for(int j=i+1;j<nums.size();j++){
if(sums[j]-sums[i]==k)
count++;
}
}
return count;
}
};
解法二: 前缀和 加 map优化 O(n)
我们知道只需要让
从[ j , i ]前缀和 pre[i] - pre[ j-1] = k即可 ,也就是 pre[i] - k = pre[ j-1]. 这里的j是 0...i -1
所以我们让mp[a]=b表示 在之前的序列中前缀和等于a的情况 出现了 b 次
那么就有点类似dp的思想,
i从0到 nums.size()-1,对于每一次循环中的i我们计算的实际上是在当前的情况下, 以i结尾的连续子数组的和为k的结果
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
// 计算[j...i] 的区间的元素和为k
// 也就是 sums[i] - sums[j-1] = k
// sums[i] - k = sums[j-1]
int pre=0,count=0;
unordered_map<int,int> mp;
mp[0]=1;
for(int i=0;i<nums.size();i++){
pre+=nums[i];
if(mp.find(pre - k) != mp.end()){
count += mp[pre - k];
}
mp[pre]++;
}
return count;
}
};