news 2026/1/29 1:22:35

【每日算法】LeetCode 560. 和为 K 的子数组

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【每日算法】LeetCode 560. 和为 K 的子数组

对前端开发者而言,学习算法绝非为了“炫技”。它是你从"页面构建者"迈向"复杂系统设计者"的关键阶梯。它将你的编码能力从"实现功能"提升到"设计优雅、高效解决方案"的层面。从现在开始,每天投入一小段时间,结合前端场景去理解和练习,你将会感受到自身技术视野和问题解决能力的质的飞跃。------ 算法:资深前端开发者的进阶引擎

LeetCode 560. 和为 K 的子数组:前缀和的精妙应用

1. 题目描述

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

示例 1:

输入:nums = [1,1,1], k = 2 输出:2 解释:[1,1] 与 [1,1] 为两种不同的情况(注意:虽然值相同,但索引位置不同)

示例 2:

输入:nums = [1,2,3], k = 3 输出:2 解释:[1,2] 和 [3]

约束条件:

  • 数组长度范围:1 <= nums.length <= 2 * 10⁴
  • 数组元素范围:-1000 <= nums[i] <= 1000
  • k 的范围:-10⁷ <= k <= 10⁷

2. 问题分析

2.1 问题核心

这个问题要求统计数组中连续子数组的和等于给定值k的个数。这是一个典型的子数组求和问题,需要特别注意:

  • 子数组必须是连续的
  • 数组元素可以是负数,这增加了问题的复杂性
  • 需要考虑空数组吗?题目没有明确说明,但根据示例,至少需要包含一个元素

2.2 前端视角的类比

在前端开发中,类似的问题场景包括:

  • 统计页面中连续点击次数达到特定阈值的情况
  • 计算用户行为序列中特定模式的出现次数
  • 分析性能监控数据中连续时间段内指标达标的情况

3. 解题思路

3.1 思路演进

3.1.1 暴力枚举法

最直观的想法是枚举所有可能的子数组,计算它们的和,统计等于k的数量。

3.1.2 前缀和优化

暴力法的时间复杂度为 O(n²),对于 2×10⁴ 的数据量会超时。我们需要更高效的方法。

前缀和(Prefix Sum)概念
前缀和是一种预处理技术,通过预先计算并存储数组的前缀和,可以在 O(1) 时间内计算任意子数组的和。

定义前缀和数组preSum,其中preSum[i]表示nums[0] + nums[1] + ... + nums[i-1]的和。

那么子数组nums[i..j]的和可以表示为:

sum(nums[i..j]) = preSum[j+1] - preSum[i]
3.1.3 哈希表优化

对于每个j,我们需要找到有多少个i满足preSum[i] = preSum[j+1] - k。使用哈希表可以在 O(1) 时间内完成查找。

核心公式

preSum[j+1] - preSum[i] = k => preSum[i] = preSum[j+1] - k

3.2 复杂度分析

方法时间复杂度空间复杂度是否推荐
暴力枚举O(n²)O(1)不推荐,会超时
前缀和+哈希表O(n)O(n)推荐,最优解

4. 各思路代码实现

4.1 暴力枚举法(不推荐,仅用于理解)

/** * 暴力枚举法 * @param {number[]} nums * @param {number} k * @return {number} */varsubarraySumBruteForce=function(nums,k){letcount=0;constn=nums.length;for(leti=0;i<n;i++){letsum=0;for(letj=i;j<n;j++){sum+=nums[j];if(sum===k){count++;}}}returncount;};

4.2 前缀和+哈希表法(最优解)

/** * 前缀和+哈希表法(最优解) * @param {number[]} nums * @param {number} k * @return {number} */varsubarraySum=function(nums,k){// 哈希表:键为前缀和,值为该前缀和出现的次数constmap=newMap();// 初始化:前缀和为0出现了1次(空数组的情况)map.set(0,1);letcount=0;letprefixSum=0;for(leti=0;i<nums.length;i++){// 计算当前前缀和prefixSum+=nums[i];// 如果存在某个前缀和等于 currentPrefixSum - k// 说明从那个位置到当前位置的子数组和为 kif(map.has(prefixSum-k)){count+=map.get(prefixSum-k);}// 更新当前前缀和出现的次数map.set(prefixSum,(map.get(prefixSum)||0)+1);}returncount;};

4.3 带详细注释的版本(便于理解)

/** * 前缀和+哈希表法(详细注释版) * @param {number[]} nums * @param {number} k * @return {number} */varsubarraySumWithComments=function(nums,k){// 哈希表:存储前缀和及其出现次数// 为什么需要这个哈希表?// 我们要找的是:prefixSum[j] - prefixSum[i] = k// 即:prefixSum[i] = prefixSum[j] - k// 所以对于每个j,我们需要知道之前有多少个i满足这个条件constprefixSumCount=newMap();// 为什么要初始化前缀和为0出现了1次?// 考虑整个数组从开头到某个位置的子数组和为k的情况// 即:prefixSum[j] - 0 = k,这时候prefixSum[i]为0(i为-1,空数组)prefixSumCount.set(0,1);letcurrentSum=0;// 当前前缀和letresult=0;// 结果计数for(leti=0;i<nums.length;i++){// 计算到当前位置的前缀和currentSum+=nums[i];// 核心逻辑:如果存在一个前缀和等于 currentSum - k// 那么从那个位置到当前位置的子数组和就是k// 例如:nums = [1, 2, 3], k = 3// 当i=2时,currentSum = 6// currentSum - k = 3,如果之前出现过前缀和3,那么从那个位置到当前位置的和就是3consttarget=currentSum-k;if(prefixSumCount.has(target)){// 可能有多个位置的前缀和都等于target,所以都要加上result+=prefixSumCount.get(target);}// 更新当前前缀和的出现次数// 这里使用 || 0 来处理undefined的情况(如果该前缀和之前没出现过)prefixSumCount.set(currentSum,(prefixSumCount.get(currentSum)||0)+1);}returnresult;};

5. 各实现思路的复杂度、优缺点对比

5.1 对比表格

实现方法时间复杂度空间复杂度优点缺点适用场景
暴力枚举法O(n²)O(1)1. 思路直观简单
2. 不需要额外空间
1. 效率低下,n=20000时会超时
2. 不适合大数据量
小规模数据(n<1000)或教学演示
前缀和+哈希表O(n)O(n)1. 时间复杂度最优
2. 能处理包含负数的情况
3. 适合大规模数据
1. 需要额外O(n)空间
2. 逻辑相对复杂
大规模数据处理、生产环境推荐使用

5.2 详细分析

5.2.1 暴力枚举法
  • 时间复杂度分析

    • 外层循环:n次
    • 内层循环:平均n/2次
    • 总复杂度:O(n²)
    • 当n=20000时,操作次数约2亿次,明显超时
  • 空间复杂度:O(1),只使用了常数级别的额外空间

5.2.2 前缀和+哈希表法
  • 时间复杂度分析

    • 单次遍历数组:O(n)
    • 每次操作哈希表:平均O(1)
    • 总复杂度:O(n)
    • 当n=20000时,操作次数约2万次,效率极高
  • 空间复杂度

    • 最坏情况下,每个前缀和都不同,需要存储n个键值对
    • 空间复杂度:O(n)

6. 总结与前端应用场景

6.1 核心要点总结

  1. 前缀和思想:将子数组求和问题转化为前缀和之差的问题
  2. 哈希表优化:通过哈希表记录前缀和出现次数,实现O(1)时间查找
  3. 边界处理:注意初始化前缀和为0的情况(对应空子数组)
  4. 负数处理:由于数组元素可能为负数,不能使用双指针滑动窗口法

6.2 实际应用场景(前端视角)

6.2.1 性能监控与分析
// 监控连续时间段内API错误率达到阈值的情况consterrorRates=[0.1,0.2,0.05,0.3,0.15,0.25];constthreshold=0.5;// 统计连续时间段内错误率总和超过阈值的时间段数量functioncountErrorSpikes(errorRates,threshold){constmap=newMap();map.set(0,1);letcount=0;letprefixSum=0;for(letrateoferrorRates){prefixSum+=rate;if(map.has(prefixSum-threshold)){count+=map.get(prefixSum-threshold);}map.set(prefixSum,(map.get(prefixSum)||0)+1);}returncount;}
6.2.2 用户行为分析
// 分析用户连续操作序列// 例如:统计用户连续点击次数达到特定模式的情况constuserActions=['click','scroll','click','hover','click'];consttargetPattern=2;// 连续click的次数functioncountActionPatterns(actions,targetAction,targetCount){constmap=newMap();map.set(0,1);letcount=0;letcurrentStreak=0;for(letactionofactions){// 如果是目标行为,streak加1,否则重置为-1(或其他负值)currentStreak+=(action===targetAction?1:-1);// 查找是否有位置使得连续目标行为次数等于targetCountif(map.has(currentStreak-targetCount)){count+=map.get(currentStreak-targetCount);}map.set(currentStreak,(map.get(currentStreak)||0)+1);}returncount;}
6.2.3 数据处理与可视化
// 在数据可视化中,统计连续时间段内数据超过阈值的情况classDataAnalyzer{constructor(){this.prefixSumMap=newMap();}// 实时数据流处理processDataStream(dataStream,threshold){constresult=[];letprefixSum=0;letmap=newMap([[0,[-1]]]);// 存储前缀和及其出现的位置for(leti=0;i<dataStream.length;i++){prefixSum+=dataStream[i];// 查找满足条件的位置consttarget=prefixSum-threshold;if(map.has(target)){constpositions=map.get(target);for(letposofpositions){result.push([pos+1,i]);// 子数组的起始和结束索引}}// 更新哈希表if(!map.has(prefixSum)){map.set(prefixSum,[]);}map.get(prefixSum).push(i);}returnresult;}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/27 6:37:04

ImageViewer:简单高效的跨平台图片浏览终极方案

ImageViewer&#xff1a;简单高效的跨平台图片浏览终极方案 【免费下载链接】ImageViewer An image viewer la Twitter 项目地址: https://gitcode.com/gh_mirrors/im/ImageViewer 在现代数字生活中&#xff0c;图片浏览已成为我们日常工作和娱乐的重要组成部分。无论你…

作者头像 李华
网站建设 2026/1/27 8:44:18

如何快速掌握ArcGIS Python API:地理空间分析完整指南

ArcGIS Python API 是一个功能强大的地理空间分析工具包&#xff0c;专为Python开发者设计。它提供了丰富的地理数据处理、地图可视化、空间分析等功能&#xff0c;让用户能够轻松处理复杂的地理信息任务。无论你是GIS专业人士还是数据分析师&#xff0c;这个API都能帮助你高效…

作者头像 李华
网站建设 2026/1/26 20:18:25

3步搞定version-manager:新手也能轻松掌握的跨平台SDK管理神器

3步搞定version-manager&#xff1a;新手也能轻松掌握的跨平台SDK管理神器 【免费下载链接】version-manager &#x1f525; A general version manager for multiple sdks, such as Java, Go, Node.js, Deno, Bun, .Net, Python, PyPy, PHP, Kotlin, Scala, Groovy, Flutter, …

作者头像 李华
网站建设 2026/1/27 8:42:31

多Agent协作入门:基于A2A协议的Agent通信(中)

A2A协议的三大角色A2A 即 Agent-to-Agent&#xff0c;它定义了三个关键的角色&#xff0c;它们各司其职互相配合&#xff0c;支撑多个Agent的运行。那么&#xff0c;都是哪几个角色呢&#xff1f;下面告诉你&#xff1a;image角色1&#xff1a;用户&#xff08;User&#xff09…

作者头像 李华
网站建设 2026/1/28 6:17:04

sensitive-word:一个简单易用的敏感词过滤框架

文章&#xff0c;分享一个开源项目&#xff1a;sensitive-word 。Github 地址&#xff1a;https://github.com/houbb/sensitive-wordsensitive-word 是一个功能强大的 Java 敏感词过滤框架&#xff0c;它不仅提供了基础的敏感词检测功能&#xff0c;还支持单词标签分类分级、繁…

作者头像 李华
网站建设 2026/1/28 2:59:42

Lottie-Web终极指南:零代码实现专业级Web动画

Lottie-Web终极指南&#xff1a;零代码实现专业级Web动画 【免费下载链接】lottie-web 项目地址: https://gitcode.com/gh_mirrors/lot/lottie-web 还在为设计师的AE动画无法完美呈现在网页上而烦恼&#xff1f;前端工程师还原动效耗时耗力&#xff1f;Lottie-Web为你提…

作者头像 李华