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

实例与展示

三、结语

再见!

相关推荐
pink大呲花几秒前
使用 Axios 进行 API 请求与接口封装:打造高效稳定的前端数据交互
前端·vue.js·交互
samuel9188 分钟前
uniapp通过uni.addInterceptor实现路由拦截
前端·javascript·uni-app
泯泷17 分钟前
JavaScript随机数生成技术实践 | 为什么Math.random不是安全的随机算法?
前端·javascript·安全
benben04418 分钟前
Unity3D仿星露谷物语开发35之锄地动画
前端·游戏·游戏引擎
爱是小小的癌30 分钟前
[第十六届蓝桥杯 JavaB 组] 真题 + 经验分享
经验分享·算法·蓝桥杯
WebInfra31 分钟前
🔥 Midscene 重磅更新:支持 AI 驱动的 Android 自动化
android·前端·测试
八了个戒1 小时前
「数据可视化 D3系列」入门第八章:动画效果详解(让图表动起来)
开发语言·前端·javascript·数据可视化
自由鬼2 小时前
AI当前状态:有哪些新技术
人工智能·深度学习·算法·ai·chatgpt·deepseek
奋进的小暄2 小时前
贪心算法(20)(java)整数替换
开发语言·算法
拉不动的猪2 小时前
无缝适配 PC 和移动端‌我们要注意哪些点呢
前端·javascript·面试