1.题目描述
给你一个整数数组 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来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.解题思路
转化问题为,求前缀和数组中后面任意一个数减去前面任意一个数等于k的对数有多少个
扫描一遍数组, 对每个i计算累计和sum并判断map内是否有sum-k,求前缀和数组中后面任意一个数减去前面任意一个数等于k的对数有多少个 ,相当于 求前缀和数组为sum-k的值有多少个,再使用map记录出现同样的和的次数
对于一开始的情况,下标 0 之前没有元素,可以认为前缀和为 0,个数为 1 个,因此,提前加入hashPreSum[0]=1
细节可以参考labuladong算法小抄 前缀和技巧
下面这个解法的时间复杂度 O(N^2) 空间复杂度 O(N) , 并不是最优的解法。
因此可以利用hash进行优化。
int subarraySum(int[] nums, int k) {
int n = nums.length;
// 构造前缀和
int[] sum = new int[n + 1];
sum[0] = 0;
for (int i = 0; i < n; i++)
sum[i + 1] = sum[i] + nums[i];
int ans = 0;
// 穷举所有⼦数组,注意i从1开始
for (int i = 1; i <= n; i++)
for (int j = 0; j < i; j++)
// sum of nums[j..i-1]
if (sum[i] - sum[j] == k)
ans++;
return ans;
}
3.代码实现
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
hashPreSum={}
cur=0
res=0
# 前缀和本身等于k的情况
hashPreSum[0]=1
for num in nums:
cur+=num
# hash[cur-k] 为满足当前数cur减去前面cur-k等于k的情况数
res+=hashPreSum.get(cur-k,0)
hashPreSum[cur]=hashPreSum.get(cur,0)+1
return res