中等LeetCode 560可逐步演示引导学习
和为 K 的子数组
前缀和:把区间和变成两个前缀的差
维护从开头到当前元素的前缀和,用哈希表记录每个前缀和出现次数;当前前缀和减 k 出现过几次,就有几个以当前位置结尾的合法子数组。
时间复杂度 O(n)空间复杂度 O(n)
题单:面试热题
题目描述
给定一个整数数组 nums 和一个整数 k,统计有多少个连续子数组的元素和恰好等于 k。数组可能包含负数。
学习目标
把区间和转成前缀和之差,理解哈希计数的含义,写出 O(n) 实现。
已完成 0 / 6 阶段
诊断
为什么不能滑窗
有负数时,窗口和还单调吗?
建议先完成当前阶段(提示 / 检查 / 自评),再进入下一步;也可以直接跳过。
解题思路
核心思想
维护从开头到当前元素的前缀和,用哈希表记录每个前缀和出现次数;当前前缀和减 k 出现过几次,就有几个以当前位置结尾的合法子数组。
为什么需要它
暴力枚举起点和终点是 O(n²)。前缀和把区间和变成两个前缀和的差,配合哈希表把找起点降到 O(1)。
第一反应:直觉方案
枚举所有起点,向后累加并判断是否等于 k;能工作,但最坏 O(n²)。
关键洞察
区间 [i,j] 的和 = prefix[j] - prefix[i-1];要让它等于 k,只需 prefix[i-1] = prefix[j] - k。遍历时查询历史前缀和出现次数即可。
时间复杂度 O(n)空间复杂度 O(n)
易错点
- 哈希表必须先放入 {0:1},表示空前缀。
- 先查询 sum-k,再把当前 sum 写入表。
- 有负数,不能用普通滑动窗口。
逐步演示
参考代码
1function subarraySum(nums, k) {
2 const count = new Map();
3 count.set(0, 1);
4
5 let sum = 0;
6 let result = 0;
7
8 for (let i = 0; i < nums.length; i++) {
9 sum += nums[i];
10 result += count.get(sum - k) || 0;
11 count.set(sum, (count.get(sum) || 0) + 1);
12 }
13
14 return result;
15}
效果图
当前场景
前缀和次数
0: 1
第 1 / 11 步