文章目录
560. 和为 K 的子数组
题目来源
题目分析
给你一个整数数组
nums
和一个整数k
,请你统计并返回 该数组中和为k
的连续子数组的个数。
题目难度
- 难度:中等
题目标签
- 标签:数组、哈希表、前缀和
题目限制
1 <= nums.length <= 2 * 10^4
-10^3 <= nums[i] <= 10^3
-10^7 <= k <= 10^7
解题思路
思路:前缀和 + 哈希表
- 问题定义:
- 需要找到数组中和为
k
的所有连续子数组。
- 需要找到数组中和为
- 核心算法:
- 使用前缀和数组来记录从数组开始到当前位置的累积和。问题转换为找前缀和数组中所有
sj-si=k
的位置,找sj-si=k
等价于找sj=si+k
,可以使用哈希表记录si
,如果sj-k
在哈希表中,则说明存在sj=si+k
,即sj-si=k
- 使用哈希表来记录每个前缀和出现的次数,以便快速查找满足条件的子数组数量。
- 使用前缀和数组来记录从数组开始到当前位置的累积和。问题转换为找前缀和数组中所有
核心算法步骤
- 初始化前缀和数组:
- 创建一个前缀和数组
pre
,长度为nums.length + 1
,初始化pre[0] = 0
。
- 创建一个前缀和数组
- 计算前缀和:
- 遍历
nums
,计算每个位置的前缀和pre[i + 1] = pre[i] + nums[i]
。
- 遍历
- 使用哈希表记录前缀和:
- 初始化哈希表
map
,并设置map.put(0, 1)
来处理前缀和刚好等于k
的情况。 - 遍历前缀和数组
pre
,对于每个前缀和sj
,检查sj - k
是否在哈希表中,如果在,则累加其出现的次数到答案中。
- 初始化哈希表
- 更新哈希表:
- 将当前前缀和
sj
加入哈希表,并更新其出现次数。
- 将当前前缀和
代码实现
以下是前缀和 + 哈希表方法的 Java 代码实现:
public int subarraySum(int[] nums, int k) {
int ans = 0;
int n = nums.length;
int[] pre = new int[n + 1];
pre[0] = 0;
for (int i = 0; i < n; i++) {
pre[i + 1] = pre[i] + nums[i];
}
Map<Integer, Integer> map = new HashMap<>(n + 2);
map.put(0, 1);
for (int sj : pre) {
ans += map.getOrDefault(sj - k, 0);
map.put(sj, map.getOrDefault(sj, 0) + 1);
}
return ans;
}
代码解读
- 前缀和计算:通过累加数组元素来构建前缀和数组。
- 哈希表使用:通过哈希表记录前缀和出现的次数,以便快速查找满足条件的子数组数量。
性能分析
- 时间复杂度:
O(n)
,其中n
是数组nums
的长度。因为每个元素只被遍历一次。 - 空间复杂度:
O(n)
,用于存储前缀和数组和哈希表。
测试用例
你可以使用以下测试用例来验证代码的正确性:
public static void main(String[] args) {
int[] nums = {1, 1, 1};
int k = 2;
System.out.println(subarraySum(nums, k)); // 输出: 2
}
扩展讨论
有没有其他方法可以解决这个问题?
- 滑动窗口:如果数组的值全部非负,可以尝试使用滑动窗口来找到和为
k
的子数组。
总结
本题通过前缀和与哈希表的结合,有效地解决了查找和为 k
的子数组数量的问题,提供了一种时间复杂度为 O(n)
的解法。