力扣热题100刷题-subString-560-和为 K 的子数组
560. 和为 K 的子数组
题意
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。
思路
易错点 / 卡点
- 负数存在:数组中可能包含负数,这意味着子数组的和不具有单调性。即使当前和已经大于
k,加上一个负数后仍可能等于k。因此,不能简单地用滑动窗口来优化。 -
O(n^2) 超时:最直观的暴力解法是枚举所有子数组的起点和终点,计算其和,时间复杂度为 O(n^3) 或优化后的 O(n^2),在数据量较大时会超时。
-
第一想法: 通过两层循环枚举所有连续子数组。外层循环固定子数组的右端点
i,内层循环枚举左端点j,计算[j, i]区间的和。 -
为什么不行: 时间复杂度为 O(n^2),当
nums数组的长度很大时,会导致性能问题,无法通过所有测试用例。 - 最终解法:前缀和 + 哈希表
这是解决此类问题的经典优化方法。
- 定义
pre[i]为nums[0..i-1]的元素和。那么,任意连续子数组nums[j..i]的和就可以表示为pre[i+1] - pre[j]。 - 我们要求的是
pre[i+1] - pre[j] == k。 - 将这个等式变形为
pre[j] = pre[i+1] - k。 - 这个等式是本题解法的关键。它的含义是:对于当前遍历到的位置
i,我们只需要找到在它之前,有多少个位置j的前缀和pre[j]恰好等于pre[i+1] - k。 - 我们可以使用一个哈希表(HashMap)来记录每个前缀和值出现的次数。哈希表的
key是前缀和的值,value是该前-缀和值已经出现过的次数。 - 我们从左到右遍历数组,计算当前的前缀和
current_sum。在哈希表中查找current_sum - k是否存在。如果存在,说明找到了若干个满足条件的子数组,将对应的value累加到最终结果ans中。 - 查询完后,将当前的前缀和
current_sum存入哈希表(或更新其出现次数),供后续的计算使用。 - 初始化技巧:为了处理从索引 0 开始的子数组(即
pre[j]中j=0的情况,其前缀和为 0),需要在哈希表中预先放入(0, 1),表示和为 0 的前缀和已经出现过 1 次。
- 定义
核心思路(本质)
本题的本质是将 “求解定值子数组和” 的问题,通过 “前缀和” 技巧,转化为一个 “寻找两个前缀和之差为定值” 的问题。这与 “两数之和” 问题的思想非常相似,因此可以利用 哈希表 来高效地进行查找,将时间复杂度从 O(n^2) 优化到 O(n)。
总结
(一句话总结触发器)
看到 “连续子数组和”、“定值 k” 且包含负数 → 前缀和 + 哈希表。