题目描述
给你一个整数数组 nums
和一个整数 k
,请你统计并返回该数组中和为 k
的连续子数组的个数。
样例
输入:nums = [1,1,1], k = 2
输出:2
输入:nums = [1,2,3], k = 3
输出:2
限制
1 <= nums.length <= 2 * 10^4
-1000 <= nums[i] <= 1000
-10^7 <= k <= 10^7
算法
(前缀和,哈希表) $O(n)$
- 对原数组求前缀和后,一个和为
k
的子数组即为一对前缀和的差值为k
的位置。 - 遍历前缀和数组,用
unordered_map
哈希表记录每个前缀和出现的次数。特别地,初始时前缀和为0
需要被额外记录一次。 - 遍历过程中,对于当前前缀和
tot
,累加之前tot - k
前缀和出现的次数。
时间复杂度
- 每个位置仅遍历一次,哈希表单次操作的时间复杂度为常数,故总时间复杂度为 $O(n)$。
空间复杂度
- 需要 $O(n)$ 的额外空间存储哈希表。
C++ 代码
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> hash;
int tot = 0, ans = 0;
hash[0] = 1;
for (auto x : nums) {
tot += x;
ans += hash[tot - k];
hash[tot]++;
}
return ans;
}
};
大佬们都水平太高,没有点到小白对这题的盲点:数的范围是有正负的,所以前缀和是可以有重复的,而不是递增的。
为什么hash[tot]++;在ans += hash[tot - k];这个后面呢
避免
k==0
的情况Java代码
对原数组求前缀和后,一个和为 k 的子数组即为一对前缀和的差值为 k 的位置。
这句话对我帮助很大~hash[0] = 1;
这个是什么意思呢?
0 这个前缀和初始的时候就已经出现过一次了
3q
ans += hash[tot - k];
这句话是什么意思,为什么要带上上一次的计算结果?这个不是上一次的计算结果呀
ans = ans + hash[tot - k];
等号右边的ans代表什么呢?没弄明白这个运行过程(感觉模拟了还是不知道为什么要这么写)这个是累计答案呀,假设当前的前缀和为
tot
,则我们累加之前的前缀和为tot - k
的个数。是不是说前缀和为
tot - k
到前缀和为tot
刚好形成一个区间,ans++;对滴,但前缀和为
tot - k
的情况有很多,所以ans
需要累加hash[tot-k]
OK!谢谢zc大佬。
请问为什么让ans累加hash[tok-k]呢,如果tok-k出现了一次,则加1,若tok-k出现了两次,则加2,但问题是这个2里面包含了之前的1次啊,这样难道不会重复吗?
这样才是正确的呀
这两个代表不同的子数组
tot-k<0时不会越界吗
hash
是unordered_map
类,不是数组明白了