一、题目描述
给你一个整数数组 nums
和一个整数 k
,请你统计并返回 该数组中和为 k
的子数组的个数 。
子数组是数组中元素的连续非空序列。
示例 1:
ini
输入: nums = [1,1,1], k = 2
输出: 2
示例 2:
ini
输入: nums = [1,2,3], k = 3
输出: 2
提示:
1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107
二、题解(前缀和)
js
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var subarraySum = function(nums, k) {
let count = 0; // 用于存储和为 k 的子数组的个数
let sum = 0; // 记录前缀和
const sumMap = new Map(); // 使用 Map 存储前缀和及其出现的次数
// 初始化:前缀和为 0 的情况出现一次,这是为了处理子数组从数组开头就开始的情况
sumMap.set(0, 1);
for (let i = 0; i < nums.length; i++) {
sum += nums[i]; // 更新前缀和
// 检查是否存在 sum - k 的前缀和
// 如果存在,则说明从某个位置到当前位置的子数组的和等于 k
if (sumMap.has(sum - k)) {
count += sumMap.get(sum - k); // 加上所有和为 sum - k 的子数组的个数
}
// 更新当前前缀和的计数
sumMap.set(sum, (sumMap.get(sum) || 0) + 1);
}
return count; // 返回和为 k 的子数组的个数
};
核心思想
利用前缀和 记录从数组开头到每个位置的累加和,并用哈希表 (Map) 存储这些前缀和及其出现的次数。通过快速查找是否存在前缀和 sum - k
来判断是否存在和为 k
的子数组,并将这些子数组的个数累加起来,从而高效地统计所有满足条件的子数组。
详细解释
1. 核心概念
-
前缀和:
prefixSums[i]
=nums[0]
+nums[1]
+ ... +nums[i]
- 作用:快速计算子数组和。
sum(nums[i]...nums[j])
=prefixSums[j]
-prefixSums[i-1]
(如果 i=0, 则为prefixSums[j]
)
- 作用:快速计算子数组和。
-
哈希表 (Map): 存储
<前缀和, 出现次数>
,快速查找特定前缀和。
2. 算法步骤详解
-
初始化:
inilet count = 0; // 和为 k 的子数组个数 let sum = 0; // 前缀和 const sumMap = new Map(); // <前缀和, 出现次数> sumMap.set(0, 1); // 初始化:前缀和为 0 出现 1 次 (处理从数组开头开始的子数组)
count
: 计数器,记录结果。sum
: 保存当前前缀和。sumMap
: 存储前缀和及其频率。sumMap.set(0, 1)
: 关键! 允许算法正确处理类似于nums = [k]
的情况。
-
遍历
nums
数组:scssfor (let i = 0; i < nums.length; i++) { sum += nums[i]; // 更新前缀和 if (sumMap.has(sum - k)) { count += sumMap.get(sum - k); // 找到和为 k 的子数组 } sumMap.set(sum, (sumMap.get(sum) || 0) + 1); // 更新前缀和计数 }
-
sum += nums[i]
: 累加当前元素,更新前缀和。 -
if (sumMap.has(sum - k))
: 核心判断!- 如果存在
sum - k
,意味着存在一个索引j < i
,使得prefixSums[j] == sum - k
。 - 因此,
sum(nums[j+1]...nums[i]) == k
,即找到了一个和为k
的子数组。 count += sumMap.get(sum - k)
: 累加和为sum - k
的前缀和出现的次数。
- 如果存在
-
sumMap.set(sum, (sumMap.get(sum) || 0) + 1)
: 更新sum
的出现次数。 如果sum
已经存在,则增加计数; 否则,设置为 1。
-
-
返回结果:
kotlinreturn count;
- 返回
count
,即和为k
的子数组的总数。
- 返回
实例与展示










三、结语
再见!