1. 和为 K 的子数组
题目链接:560. 和为 K 的子数组
算法思路:前缀和 + 哈希表
sum[i] 表示(0,i)之间的前缀和,当 x 为起始位置,i 元素结尾的数组和为 k 时,也就是相当于在(0,x)区间前缀和为 sum - k,因此也就是求出在(0,i-1)内有多少个前缀和为 sum - k 的数组即可。
但是也不需要真的定义一个前缀和,使用 sum 累加计算即可。前缀和处理的时机应该是遍历到哪个元素,就计算哪个元素之前的前缀和,因为当整个前缀和都预处理出来时,在哈希表中寻找可能会重复还未遍历到的元素的前缀和。
算法代码:
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> hash = new HashMap<>();
hash.put(0, 1);
int sum = 0, ret = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
ret += hash.getOrDefault(sum - k, 0);
hash.put(sum, hash.getOrDefault(sum, 0) + 1);
}
return ret;
}
2. 和可被 k 整除的子数组
题目链接:974. 和可被 k 整除的子数组
算法思路:前缀和 + 哈希表
该题和上道题基本类似,只不过用到了同余定理:(a - b) % k == 0 得到 a % k == b % k,该题也就是找在(0,i-1)区间内有多少个前缀和的余数为 sum[i] % k。
细节:前缀和中存的应该是前缀和的余数。
算法代码:
public int subarraysDivByK(int[] nums, k) {
Map<Integer, Integer> hash = <>();
hash.put(, );
, ret = ;
( ; i < nums.length; i++) {
sum += nums[i];
(sum % k + k) % k;
ret += hash.getOrDefault(r, );
hash.put(r, hash.getOrDefault(r, ) + );
}
ret;
}


