解题思路(枚举/前缀和+哈希)
方法一:枚举
考虑以
i
i
i结尾和为
k
k
k的连续子数组个数,我们需要统计符合条件的下标
j
j
j 的个数,其中 0≤
j
j
j≤
i
i
i 且 [
j
j
j…
i
i
i] 这个子数组的和恰好为
k
k
k 。
那么我们可以首先遍历
i
i
i 从0到
n
n
n,
j
j
j从
i
i
i到0,如果我们知道 [j,i] 子数组的和,就能 O(1) 推出 [j−1,i] 的和,因此这部分的遍历求和是不需要的,我们在枚举下标 j 的时候已经能 O(1) 求出 [j,i] 的子数组之和。实际上两层遍历即可枚举出所有的子数组。
- 时间复杂度:O(n2),枚举子数组开头和结尾需要 O(n2 ) 的时间,其中求和需要 O(1) 的时间复杂度,因此总时间复杂度为 O(n2 )。
- 空间复杂度:O(1)
cpp代码实现(python写 n2会超时,所以这里用了cpp)
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int count = 0;
for (int start = 0; start < nums.size(); ++start) {
int sum = 0;
for (int end = start; end >= 0; --end) {
sum += nums[end];
if (sum == k) {
count++;
}
}
}
return count;
}
};
方法二:前缀和+哈希表
- 通过前缀和,任意范围的子数组 [i, j) 的元素和就等于 preSum[j] - preSum[i],但要注意的是,我们计算前缀和的时候,每次累加 nums[i] 实际上是在处理前缀和 preSum[i+1],因此我们要预先将 preSum[0] = 0 这个前缀和加入哈希表,即前缀和 0 出现了 1次。
- 我们要查找的就是前缀和数组中满足 j > i 且 preSum[j] - preSum[i] = k 的下标对 (i,j) 的个数。我们可以借助哈希表存储已经遍历过的元素,即出现过的 preSum[i]。当我们遍历到 preSum[j] 的时候,我们就是要找在这之前,有多少个 preSum[i] = preSum[j] - k。
python代码实现
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
ans = s = 0
cnt = defaultdict(int)
cnt[0] = 1 # s[0]=0 单独统计
for x in nums:
s += x
ans += cnt[s - k]
cnt[s] += 1
return ans