560. 和为 K 的子数组

中等 含交互动画

学完这道你应该能: 说清它为什么用「哈希」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

给整数数组 nums 和整数 k,求连续子数组的和等于 k 的个数(数组可能含负数)。

nums = [1, -1, 1]
k = 1
输出 = 3

思路解析

把每个起点到每个终点的段都加一遍能做,可数据量一大就吃力,而且没利用上「前缀和之差」这个巧劲。

转折:记 pre 为从头加到当前的累加和,那么一段 (i, j] 的和 = pre[j] − pre[i]。要它 = k,就是找前面有多少个 pre[i] 正好等于 pre[j] − k。于是边走边把出现过的前缀和计数存哈希表,到每个位置查一下 pre−k 出现过几次即可。初始放 {0:1} 代表「啥都没加」。

初始化:开局先塞 {0:1}:代表「啥都没加」的前缀和 0。这是为了能数到「从下标 0 开头」那种段。pre=0、count=0。

i=0 值1 · 算 pre:加上 nums[0]=1,前缀和 pre=1。先别急着记,先拿它去查。

i=0 · 查 pre−k 命中 + 记:查 pre−k = 0,表里有 1 个 0!对应子数组就是开头的 [1],count=1。然后把 pre=1 记进表。先查后记,才不会把自己算进去。

i=1 值−1 · 算 pre(负数):加上 nums[1]=−1,pre 从 1 变回 0。负数让前缀和下降——这就是为什么不能用滑动窗口,只能靠前缀和+哈希。

i=1 · 查 pre−k 落空 + 记:查 pre−k = −1,表里没有,这一步落空,count 不加(负例)。再记 pre=0:seen[0] 从 1 变成 2——前缀和 0 已经出现过两次了,这很关键。

i=2 值1 · 算 pre:加上 nums[2]=1,pre 又回到 1。去查表。

i=2 · 查命中 2 次 → count += 2:查 pre−k = 0,表里有 2 个 0!所以一次加 2,对应整段 [1,−1,1] 和末尾 [1]。这就是存「次数」而非「有没有」的意义:同一个前缀和出现几次,就有几段以这里结尾。

记 pre=1 · 扫描结束:别忘了照例把当前 pre=1 记进表。数组扫完,count = 3:[1]、[1,−1,1]、末尾 [1] 三段,全程只扫了一遍。

「连续子数组求和/计数」的通杀套路:把区间和转成前缀和之差,再用哈希表 O(1) 查有没有需要的那个前缀和

参考代码(Python)

Python
1def subarraySum(nums, k):
2    from collections import defaultdict
3    seen = defaultdict(int); seen[0] = 1     # 关键:和为 0 出现 1
4    pre = 0; count = 0
5    for x in nums:
6        pre += x
7        count += seen[pre - k]               # 先查:有几个前缀和 = pre-k
8        seen[pre] += 1                       # 后记:把当前前缀和计数
9    return count

复杂度分析

  • 时间复杂度:O(n) —— 一遍扫描
  • 空间复杂度:O(n) —— 哈希表存前缀和

套路模板

骨架就这几行。两个铁律:哈希表初始化 {0:1}、先查 pre−k 再记 pre。顺序反了答案就错。

Python
1seen = {0: 1}        # 别忘了这一项
2pre = count = 0
3for x in nums:
4    pre += x
5    count += seen.get(pre - k, 0)   # 先查
6    seen[pre] = seen.get(pre, 0) + 1 # 后记

易错点

  • 错误写法:忘了初始化 seen = {0: 1}正确写法:一开始就放 {0: 1}(少了它,「从下标 0 开头、整段和为 k」的情况会被漏掉)
  • 错误写法:查 k − pre正确写法:查 pre − k(区间和 = pre[j] − pre[i] = k,所以要找的是 pre[i] = pre[j] − k)
  • 错误写法:先记 pre 再查(顺序反了)正确写法:先查 pre−k,再记 pre(反了会把当前这个前缀和也算进候选,凭空多算)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →22. 括号生成 ← 返回题库