一、题目要求
给你一个整数数组 nums
和一个整数 k
,请你统计并返回 该数组中和为 k
的子数组的个数 。
子数组是数组中元素的连续非空序列。
示例 1:
输入:nums = [1,1,1], k = 2 输出:2
示例 2:
输入:nums = [1,2,3], k = 3 输出:2
提示:
1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107
二、解法1-暴力破解 O(N^2) 会超时
枚举所有情况
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int ret = 0;
for(int i = 0;i < nums.size();i++)
{
int sum = 0;
for(int j = i;j < nums.size();j++)
{
sum+=nums[j];
if(sum == k)
ret++;
}
}
return ret;
}
};
三、解法2-前缀和+哈希表 O(N)
前缀和:
如果用sum[i],表示下标序列 [ 0 , i ] 的和,sum[i] 就叫做序列 [ 0 , i ]的前缀和,那么一个任意序列 [ j , i ] 的序列和可以表示为:sum[i]-sum[ j-1 ]。如果上述序列的序列和正好等于 K,那么就有一个序列符合条件。
哈希表:
使用 map ,以前缀和作为键,前缀和出现的次数作为值,每次可获得一个新的前缀和,判断符合条件的其他前缀和的数量(sum[i]-K),然后累加即可。
注意:还没遍历数组时哈希表默认有一个{0,1}的元素,否则若一个前缀和正好等于K(它需要0),也无法计算在内
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int ret = 0;
unordered_map<int, int> map;
map[0] = 1;
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
auto it = map.find(sum - k);
if (it != map.end()) {
ret += map[sum-k];
}
map[sum]++;
}
return ret;
}
};