636 字
3 分钟
和为 K 的子数组

题目描述#

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。

子数组是数组中元素的连续非空序列。

解题思路#

  1. 前缀和转换
    • 将子数组和问题转化为前缀和之差问题
  2. 哈希表优化
    • 使用哈希表记录各前缀和出现次数
  3. 实时计算
    • 遍历时计算当前前缀和 curr_sum
  4. 差值匹配
    • 查找 curr_sum - k 是否在历史前缀和中
  5. 计数更新
    • 匹配成功则累加对应出现次数
  6. 更新存储
    • 将当前前缀和加入哈希表

关键洞察#

  1. 前缀和性质
    • sum[i..j] = prefix[j] - prefix[i-1]
  2. 两数差转化
    • prefix[j] - prefix[i] = k 等价于 prefix[i] = prefix[j] - k
  3. 哈希表高效查询
    • O(1) 时间查询历史前缀和
  4. 初始化技巧
    • 预先存入 {0:1} 处理从头开始的子数组
  5. 顺序处理
    • 单次遍历完成计数,避免嵌套循环
  6. 负数和处理
    • 天然支持含负数的数组

复杂度分析#

指标说明
时间复杂度O(n):单次遍历数组
空间复杂度O(n):哈希表存储前缀和
最优情况O(n):所有元素相同时
最坏情况O(n):前缀和均不同时

代码实现#

/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var subarraySum = function (nums, k) {
let result = 0, sum = 0;
const map = { 0: 1 };
for (const num of nums) {
sum += num;
if (map[sum - k]) {
result += map[sum - k];
}
map[sum] = (map[sum] || 0) + 1
}
return result;
};
use std::collections::HashMap;
impl Solution {
pub fn subarray_sum(nums: Vec<i32>, k: i32) -> i32 {
let mut sum = 0;
let mut result = 0;
let mut map = HashMap::new();
map.insert(0, 1);
for num in nums {
sum = sum+num;
if let Some(&count) = map.get(&(sum-k)) {
result+=count;
}
*map.entry(sum).or_insert(0)+=1;
}
return result;
}
from collections import defaultdict
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
map = defaultdict(int)
map[0] = 1
count = 0
sum = 0
for num in nums:
sum+=num
if sum - k in map:
count += map[sum-k]
map[sum]+=1
return count

实际应用场景#

  1. 金融分析:寻找特定收益率的交易区间`
  2. 基因序列:DNA序列中特定碱基和片段定位`
  3. 流量监控:网络流量中特定数据包序列检测`
  4. 库存管理:库存变化满足特定总量的时段`

相似题目#

和为 K 的子数组
https://website-truelovings-projects.vercel.app/posts/algorithms/和为-k-的子数组/
作者
欢迎来到StarSky的网站!
发布于
2025-08-29
许可协议
CC BY-NC-SA 4.0