一分钟解决 | 高频面试算法题——和为 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 的子数组的总数。

实例与展示

三、结语

再见!

相关推荐
冻柠檬飞冰走茶9 小时前
PTA基础编程题目集 7-15 计算圆周率(C语言实现)
c语言·开发语言·数据结构·算法
问商十三载9 小时前
AI 引擎生成式优化两种思路怎么选?2026 对比分析附选型方法
人工智能·算法
程序员黑豆9 小时前
鸿蒙应用开发:@Link 装饰器实现父子组件双向同步
前端·后端·harmonyos
前端炒粉9 小时前
简易实现ssr
开发语言·前端·javascript
顶级自由人9 小时前
【前端菜鸟的补课01】Zod 与 PostgreSQL 全栈数据工程教学
前端·后端·程序员
swipe10 小时前
11|(前端转全栈)购物车不能只存在前端:用户维度数据如何在后端落库
前端·后端·全栈
hanlin0310 小时前
刷题笔记:力扣第704、977、209题(数组相关)
笔记·算法·leetcode
陕西企来客11 小时前
生成式引擎优化(GEO)行业白皮书:从流量分配到认知占有的战略跃迁
人工智能·算法·机器学习·技术好geo优化
清泓y11 小时前
深度学习算法
算法·ai·语言模型·面试