原题:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
一开始以为是滑动窗口问题,写完提交才发现没考虑负数。。。寄
总之滑动窗口一般只适用于字符串相关的子串问题。子数组的话,得考虑前缀和了
基本思路:(前缀和 + 哈希表)
1. 首先,前缀和是指:数组从下标0到当前位置所有元素之和
如:对于 [1,2,3,4,5],其前缀和数组为 [1,3,6,10,15]
2. 那么,前缀和与子数组有什么关系?仍以 [1,2,3,4,5] 为例:
比如说我们想求下标 1 到 3 之间的和,即 2 + 3 + 4 = 9
在前缀和数组中,该值正好为下标 3 与 0 的差,即 10 - 1 = 9
由此我们可以得出结论:任意子数组的和,均可以通过不同元素的前缀和之差求出
3. 因此,我们得到如下等式:当前元素前缀和 - 之前求得的某个前缀和 = K
当数组中存在某个子数组之和为 K 时,上述等式成立
移项一下:之前求得的某个前缀和 = 当前元素前缀和 - K
这与经典“两数之和”问题有点类似了:
我们采用哈希表:键 - 前缀和,值 - 该前缀和出现的次数
4. 最终,我们得出关键步骤:
遍历,计算当前前缀和 sum
寻找与 sum 之差正好为 K 的其他前缀和:即 find( 当前元素前缀和 - K )
这样的“其他前缀和”有多少个,最终的答案就增加多少
最后,将“当前前缀和”也插入哈希表
代码如下:
int subarraySum(vector<int>& nums, int k) {
int sum = 0; //当前的前缀和
int ans = 0; //最终答案
unordered_map<int, int> pre_sum; //哈希表
pre_sum[0] = 1; //初始化哈希表(考虑特殊情况:数组的首元素即为K时)
for (const int& i : nums)
{
sum += i //更新前缀和
if (pre_sum.find(sum - k) != pre_sum.end()) //寻找与sum之差为K的其他前缀和
{
ans += pre_sum[sum - k]; //这样的每一个“其他前缀和”,都能与sum构成一个答案
}
pre_sum[sum]++; //更新哈希表
}
return ans;
}