[560. 和为K的子数组]
难度 中等
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
- 数组的长度为 [1, 20,000]。
- 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k
解法一:暴力枚举
枚举 nums[i] ... nums[j]
的所有连续的子数组和 ,其中 0 ≤ i ≤ j < nums.length
public class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
for (int start = 0; start < nums.length; ++start) {
int sum = 0;
for (int end = start; end >= 0; --end) {
sum += nums[end];//获取从 start 到 end 的累加和
//判断累加和是否等于 k
if (sum == k) {
count++;
}
}
}
return count;
}
}
解法二:前缀和 + HashMap
思路:
pre[i]
表示从0
到i
的连续的子数组和, 且pre[i]
可以由pre[i - 1]
递推得到
pre[i] = pre[i - 1] + nums[i]
假设从i
到j
连续的子数组和为k
, 则有
pre[j] - pre[i - 1] = k
简单移项可得符合条件的下标i
需要满足
pre[i - 1] = pre[j] - k
因此我们可以通过判断前缀和pre[j]
减去目标值 k
后的所得值的前缀和是否存在来得到结果
class Solution {
public int subarraySum(int[] nums, int k) {
// key:前缀和,value:key 对应的前缀和的个数
Map<Integer, Integer> preSumFreq = new HashMap<>();
// 对于下标为 0 的元素,前缀和为 0,个数为 1 ,用来处理数组中某个位置的数等于 k 的情况
preSumFreq.put(0, 1);
int preSum = 0;
int ans = 0;
for (int i = 0; i < nums.length; i++) {
preSum += nums[i];
// 先获得前缀和为 preSum - k 的个数,加到计数变量里
if (preSumFreq.containsKey(preSum - k)) {
ans += preSumFreq.get(preSum - k); //从前缀和等于 preSum - k 的所有位置到 i 位置的和为 k
}
// 维护 preSumFreq , 若该前缀和存在则 + 1 , 不存在则默认为 0
preSumFreq.put(preSum, preSumFreq.getOrDefault(preSum, 0) + 1);
}
return ans;
}
}