题目描述
给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。
示例1
输入:nums = [1,1,1], k = 2
输出: 2
解释: 此题 [1,1] 与 [1,1] 为两种不同的情况
示例2
输入:nums = [1,2,3], k = 3
输出: 2
第1种思路
前缀和,扫一遍数组,求出下标从0-i的数字之和,比如 [1, 2, 3],那么前缀和数组为[1, 3, 6]。然后两层循环,后面的和减去前面的和,即为两指针区间内的和,找到每一个满足条件的并记录,时间复杂度为O(n^2)
class Solution {
public int subarraySum(int[] nums, int k) {
int[] sum = new int[nums.length];
sum[0] = nums[0];
int ans = 0;
if(nums[0] == k){
ans++;
}
//求前缀和
for(int i = 1; i < nums.length; i++){
sum[i] = sum[i - 1] + nums[i];
if(sum[i] == k){
ans++;
}
}
//求满足条件的区间
for(int i = 0; i < nums.length; i++){
for(int j = i + 1; j < nums.length; j++){
if(sum[j] - sum[i] == k){
ans++;
}
}
}
return ans;
}
}
第2种思路
比如前j个数字的和为sum,题目要求的和为k,那么只要j前面存在数字i,i前面所有的数字和为sum - k,那么i后面到j之间的数字和就为sum-(sum-k)=k,那么结果就+1。如果j前面存在好几个和为sum-k的,那么有多少个这样的就有多少种结果,所以我们不仅要保存前缀和,还有记录每个前缀和的个数,所以用哈希表。
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
//下面做解释
map.put(0, 1);
int sum = 0;
int ans = 0;
for(int num : nums){
sum += num;
//getOrDefault方法为如果找到对应的数就取,找不到就返回第二个参数(默认值)
ans += map.getOrDefault(sum - k, 0);
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
return ans;
}
}
为什么要put(0, 1)呢,因为比如数组[1,1,1],目标值为2,那么前两个数相加为2,要找有没有和为sum-k,即0的数,如果找不到就返回默认值0了,所以这个记录就丢失了,所以要先put一个(0, 1)。