LeetCode - 560. 和为 K 的子数组
目录
题目
为什么前缀和+哈希表能找到所有和为K的子数组
正确写法
复杂度分析
题目
560. 和为 K 的子数组 - 力扣(LeetCode)
解题思路有两种主要方法:
- 暴力法:检查所有可能的子数组,计算它们的和,统计等于k的子数组数量
- 前缀和 + 哈希表:使用前缀和和哈希表来优化,这是最优解
为什么前缀和+哈希表能找到所有和为K的子数组
前缀和的本质
前缀和sum[i]表示从数组开始到第i个元素的总和:
- sum[0] = 0(空数组的和)
- sum[1] = nums[0]
- sum[2] = nums[0] + nums[1]
- ...
- sum[i] = nums[0] + nums[1] + ... + nums[i-1]
子数组和的计算
对于任意子数组nums[i...j](从索引i到j),其和可以表示为:
nums[i] + nums[i+1] + ... + nums[j] = sum[j+1] - sum[i]
如何找到所有和为K的子数组
我们要找的是所有满足sum[j+1] - sum[i] = k的(i,j)对,等价于寻找所有满足sum[i] = sum[j+1] - k的(i,j)对。
算法的关键步骤:
- 遍历数组,对于每个位置j,计算当前的前缀和sum[j+1]
- 查找是否存在之前的前缀和等于sum[j+1] - k
- 如果存在,说明从那些前缀和对应的位置到当前位置j的子数组和为k
正确写法
class Solution {
public:int subarraySum(vector<int>& nums, int k) {int count = 0;int sum = 0;unordered_map<int, int> prefixSum; // 前缀和 -> 出现次数// 初始化:空子数组的前缀和为0,出现1次prefixSum[0] = 1;for (int num : nums) {// 累加当前前缀和sum += num;// 如果存在一个前缀和为(sum-k),说明存在一个子数组的和为kif (prefixSum.find(sum - k) != prefixSum.end()) {count += prefixSum[sum - k];}// 更新当前前缀和的出现次数prefixSum[sum]++;}return count;}
};
复杂度分析
- 时间复杂度:O(n),其中n是数组长度,我们只需要遍历数组一次
- 空间复杂度:O(n),最坏情况下哈希表需要存储n个不同的前缀和