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

实例与展示

三、结语

再见!

相关推荐
不会就选b12 小时前
算法日常・每日刷题--<贪心>25
数据结构·算法
FungLeo12 小时前
成为全栈·React 管理后台篇·总复盘:从“接口能调通”到“后台值得使用”
前端·react.js·前端框架·项目复盘·成为全栈
Csvn13 小时前
并发模式:让渲染学会排队、插队和让路
前端
可乐鸡翅yeah_13 小时前
新手梳理:M3U8 线上问题,哪些是前端锅,哪些是后端锅
前端·ios·音视频·实时音视频·m3u8·音视频在线播放
Flynt13 小时前
Linear 用 1000 个 PR 换掉 styled-components,我写了 200 个按钮,把这笔账复现了一遍
前端·css·preact
JavaGuide14 小时前
NVIDIA 又开源了!这次给 AI Agent 加上权限管控
前端·后端
excel15 小时前
prisma 如何处理数据库竞态
前端·数据库·后端
千里码aicood15 小时前
基于CART算法的图书分类系统设计与实现
数据库·算法·分类
做cv的小昊16 小时前
【World Model】π0.5:a Vision-Language-Action Model with Open-World Generalization
人工智能·算法·机器学习·大模型·多模态·vla·世界模型