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

实例与展示

三、结语

再见!

相关推荐
草履虫建模15 分钟前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
华玥作者2 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
naruto_lnq2 小时前
分布式系统安全通信
开发语言·c++·算法
Mr Xu_3 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
Jasmine_llq3 小时前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
前端摸鱼匠3 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang201509283 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
爱吃rabbit的mq3 小时前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
好家伙VCC4 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
(❁´◡`❁)Jimmy(❁´◡`❁)4 小时前
Exgcd 学习笔记
笔记·学习·算法