题目
思路
- 利用前缀和,由于
p
r
e
[
i
]
=
p
r
e
[
i
−
1
]
+
n
u
m
s
[
i
]
pre[i] = pre[i-1] + nums[i]
pre[i]=pre[i−1]+nums[i],
则任意一段和为 k 的子数组可以表示为 p r e [ i ] − p r e [ j ] = k = > p r e [ i ] = p r e [ j ] + k pre[i] - pre[j] = k => pre[i] = pre[j] +k pre[i]−pre[j]=k=>pre[i]=pre[j]+k; - 由于不同段的子数组可能出现不同的和,也有可能出现重复/相同的和,可以用 hash 表记录下来,即建立一个映射关系,将出现的和的次数和 p r e [ i ] pre[i] pre[i] 联系起来。其中,hash表里和为 7 对应的次数即答案。
实现代码
// 暴力美学:20行C代码
int subarraySum(int *nums, int numsSize, int k) {
int count = 0;
// 弄个大数组做个暴力的Hash表,大概4*20M*2=160M。用calloc初始化为全零。
int *maps = (int *)calloc(1001 * 20001 * 2, sizeof(int));
// 前缀和可能是负数,把指针放到中间位置
int *map = maps + 1001 * 20001 * 1;
// 补一个最前面的前缀和,用了下标0
int sum = 0;
map[sum]++;
// 下标从1开始,注意=
for (int i = 1; i <= numsSize; i++) {
// 注意-1
sum += nums[i - 1];
if (map[sum - k] > 0) {
count += map[sum - k];
}
map[sum]++;
}
free(maps);
return count;
}