一分钟解决 | 高频面试算法题——和为 K 的子数组(前缀和)

一、题目描述

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

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

示例 1:

ini 复制代码
输入: nums = [1,1,1], k = 2
输出: 2

示例 2:

ini 复制代码
输入: nums = [1,2,3], k = 3
输出: 2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

二、题解(前缀和)

js 复制代码
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var subarraySum = function(nums, k) {
    let count = 0; // 用于存储和为 k 的子数组的个数
    let sum = 0; // 记录前缀和
    const sumMap = new Map(); // 使用 Map 存储前缀和及其出现的次数

    // 初始化:前缀和为 0 的情况出现一次,这是为了处理子数组从数组开头就开始的情况
    sumMap.set(0, 1);

    for (let i = 0; i < nums.length; i++) {
        sum += nums[i]; // 更新前缀和

        // 检查是否存在 sum - k 的前缀和
        // 如果存在,则说明从某个位置到当前位置的子数组的和等于 k
        if (sumMap.has(sum - k)) {
            count += sumMap.get(sum - k); // 加上所有和为 sum - k 的子数组的个数
        }

        // 更新当前前缀和的计数
        sumMap.set(sum, (sumMap.get(sum) || 0) + 1);
    }

    return count; // 返回和为 k 的子数组的个数
};

核心思想

利用前缀和 记录从数组开头到每个位置的累加和,并用哈希表 (Map) 存储这些前缀和及其出现的次数。通过快速查找是否存在前缀和 sum - k 来判断是否存在和为 k 的子数组,并将这些子数组的个数累加起来,从而高效地统计所有满足条件的子数组。

详细解释

1. 核心概念

  • 前缀和: prefixSums[i] = nums[0] + nums[1] + ... + nums[i]

    • 作用:快速计算子数组和。 sum(nums[i]...nums[j]) = prefixSums[j] - prefixSums[i-1] (如果 i=0, 则为 prefixSums[j])
  • 哈希表 (Map): 存储 <前缀和, 出现次数>,快速查找特定前缀和。

2. 算法步骤详解

  1. 初始化:

    ini 复制代码
      
    let count = 0; // 和为 k 的子数组个数
    let sum = 0;   // 前缀和
    const sumMap = new Map(); // <前缀和, 出现次数>
    sumMap.set(0, 1); // 初始化:前缀和为 0 出现 1 次 (处理从数组开头开始的子数组)
    • count: 计数器,记录结果。
    • sum: 保存当前前缀和。
    • sumMap: 存储前缀和及其频率。
    • sumMap.set(0, 1): 关键! 允许算法正确处理类似于 nums = [k] 的情况。
  2. 遍历 nums 数组:

    scss 复制代码
      
    for (let i = 0; i < nums.length; i++) {
        sum += nums[i]; // 更新前缀和
    
        if (sumMap.has(sum - k)) {
            count += sumMap.get(sum - k); // 找到和为 k 的子数组
        }
    
        sumMap.set(sum, (sumMap.get(sum) || 0) + 1); // 更新前缀和计数
    }
    • sum += nums[i]: 累加当前元素,更新前缀和。

    • if (sumMap.has(sum - k)): 核心判断!

      • 如果存在 sum - k,意味着存在一个索引 j < i,使得 prefixSums[j] == sum - k
      • 因此, sum(nums[j+1]...nums[i]) == k,即找到了一个和为 k 的子数组。
      • count += sumMap.get(sum - k): 累加和为 sum - k 的前缀和出现的次数。
    • sumMap.set(sum, (sumMap.get(sum) || 0) + 1): 更新 sum 的出现次数。 如果 sum 已经存在,则增加计数; 否则,设置为 1。

  3. 返回结果:

    kotlin 复制代码
      
    return count;
    • 返回 count,即和为 k 的子数组的总数。

实例与展示

三、结语

再见!

相关推荐
码熔burning2 分钟前
JVM 面试精选 20 题(续)
jvm·面试·职场和发展
yzzzzzzzzzzzzzzzzz10 分钟前
初识javascript
前端·javascript
野渡拾光1 小时前
【考研408数据结构-05】 串与KMP算法:模式匹配的艺术
数据结构·考研·算法
excel1 小时前
硬核 DOM2/DOM3 全解析:从命名空间到 Range,前端工程师必须掌握的底层知识
前端
tainshuai3 小时前
用 KNN 算法解锁分类的奥秘:从电影类型到鸢尾花开
算法·分类·数据挖掘
专注API从业者8 小时前
Python + 淘宝 API 开发:自动化采集商品数据的完整流程
大数据·运维·前端·数据挖掘·自动化
Coovally AI模型快速验证9 小时前
农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
深度学习·算法·yolo·计算机视觉·transformer·无人机
pusue_the_sun9 小时前
数据结构:二叉树oj练习
c语言·数据结构·算法·二叉树
烛阴9 小时前
TypeScript高手密技:解密类型断言、非空断言与 `const` 断言
前端·javascript·typescript
RaymondZhao3410 小时前
【全面推导】策略梯度算法:公式、偏差方差与进化
人工智能·深度学习·算法·机器学习·chatgpt