目录
题目描述
思路
思路一--滑动窗口
本来看到题目想着,我的天啊,这不是可以用滑动窗口完美解决吗?直到我看到数据可以为负数,我才开始意识到问题的严重性,最后想着使用动态规划,但是推导了半天硬是推导不出来表达式,无奈选择了暴力求解...
思路二--暴力求解
思路还是滑动窗口,但是这回遍历时右指针right一直要从左往右遍历到尽头才行,结果也不用说了,超时......
int subarraySum(vector<int>& nums, int k) {
int right = -1;
int ans = 0;
int count;
int size = nums.size();
for (int i = 0; i < size; ++i) {
count = nums[i];
right = i;
while (right < size) {
++right;
count += nums[right];
}
if (count == k) ans++;
}
return ans;
} //这道题因为数据可以是负数,所以说滑动窗口根本就解不出来!!!
思路三--前缀和+hash优化
我们来想一想为何时间复杂度这么高?!可以理解,对于每一个确定的i,我们的右指针都要从左到右遍历一遍,我们不妨换一种思路--
我们对于前缀和(从[0,i]这些元素之和),如果两个前缀和相减差为K,那么说明存在一组可行解.我们对于pre[i]来说,只要找到能使得pre[j]+K=pre[i]成立的数量即可,我们每一次更新pre[i]时,其实只要得到pre[i]-K的数量,也就得到了可行解的数量(我们可以使用hash_map).同样的我们为了缩短查找时间,考虑使用hash_map,key存储pre[i]-k,value存储前缀和为pre[i]的数量.
对这里不太理解的同学不妨看一下原题解的动画会清楚很多!
https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/
代码如下:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> m;
int pre = 0;
int ans = 0;
m.insert({ 0,1 }); //需要注意这里需要加入这一元素,比如1,2,3查找3,一减,键值为0.
for (auto& num: nums) {
pre += num;
if (m.find(pre - k) != m.end()) ans+=m[pre-k];
m[pre]++;
}
return ans;
}
补充
这里补充一点原题解中没有说的地方,我们需要初始化存储m.insert({0,1}),因为我们对于那些nums[i]==K的值(eg:3,1,1,2,4,5 .K=3) ,我们不能遗漏第一个数值三,对于这种情况,对于第一次出现pre==K的情况,我们需要进行初始化处理!