解题随记
给你一个整数数组 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
解题
重点:连续、和为k、为空
思路
因为需要连续,那就有两种连续的方式,一种是从下标0开始,也就是从头开始,这种好解决,从头遍历累加就可以了;还有一种不是从下标0开始,也就是中间部分,这种我们就要使用前缀和的方式来解决了。
前缀和举例: 数组:[3,4,7,2,-3,1,4,2] k:7
- 第一种情况的比如:[3,4]
- 第二种情况的比如:[7,2,-3,1]
第二种可以看做:[3,4,7,2,-3,1] - [3,4] = [7,2,-3,1],即我们用f(x) 表示从0开始到x这个数的和(包含x),那公式就变成了f(x) - f(y) = f(y~x)。起始第一种也可以看做是该公式的一种变种。
那答案也就呼之欲出了,我们只需要统计所有从0开始的前缀和,并且计算其与k的差值,就可以知道有多少种可能了
附代码:
public static int subarraySum(int[] nums, int k){
// 前缀和对象,key为前缀和的值,value为出现的次数
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
// 求和
int sum = 0;
// 结果集
int count = 0;
for (int num : nums) {
sum += num;
// 判断是否之前出现了与k的差相同的数,比如上面例子中的当此时num下标为5(值为1)的时候,sum此时为14,我们仅需要判断14-k(7)= 7的数是否出现过,出现则统计count次数就可以
if (map.get(sum - k) != null) {
// 这里直接加次数而不是加1是因为,我们可以知道每次出现必定下标不一样,且结尾数字的下标也不一样,所以故应该加上所有
int i1 = map.get(sum - k);
count+= i1;
}
// 放入map中,如果已经出现则次数加1,代表起点的不同
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
return count;
}
如果有不对的地方希望大家斧正哈!