当前位置: 首页 > article >正文

LeetCode 560:和为 K 的子数组 | 前缀和与哈希表

LeetCode 560和为 K 的子数组 | 前缀和与哈希表引言和为 K 的子数组Subarray Sum Equals K是 LeetCode 第 560 题难度为 Medium。题目要求在给定整数数组中找出连续子数组的元素和等于 K 的数量。这道题是前缀和与哈希表结合的经典案例展示了如何将看似 O(n²) 的问题优化到 O(n) 时间复杂度。这道题的核心挑战在于如何高效地统计和等于 K 的子数组数量。如果使用暴力枚举所有子数组时间复杂度为 O(n²)。通过使用前缀和加哈希表的方法我们可以在 O(n) 时间内解决这个问题将时间复杂度降低一个数量级。问题分析题目描述给定一个整数数组 nums 和一个整数 K返回该数组中元素和等于 K 的连续子数组的数量。例如输入 nums [1, 1, 1]K 2输出为 2因为子数组 [1, 1]索引 0-1 和 1-2的和都等于 2。输入 nums [1, 2, 3]K 3输出为 2因为子数组 [1, 2] 和 [3] 的和都等于 3。问题特点这道题的关键在于连续子数组的要求。连续子数组意味着子数组的边界必须是连续的这使得前缀和技术成为可能。如果不要求连续问题就变成了计数问题需要用不同的方法处理。另一个挑战是如何在 O(n) 时间内统计所有和为 K 的子数组。暴力方法需要枚举所有可能的子数组起点和终点时间复杂度为 O(n²)。前缀和加哈希表的方法可以将时间复杂度降低到 O(n)。前缀和分析对于连续子数组 nums[i:j]包含 i 到 j其和等于 prefixSum[j1] - prefixSum[i]其中 prefixSum[k] 是前 k 个元素的和即 nums[0:k]。因此nums[i:j] 的和等于 K 当且仅当 prefixSum[j1] - prefixSum[i] K即 prefixSum[i] prefixSum[j1] - K。这个等式告诉我们对于位置 j1 的前缀和如果存在 i 使得 prefixSum[i] prefixSum[j1] - K那么以 i 为起点的子数组 nums[i:j] 的和就等于 K。因此我们只需要统计对于每个位置有多少个之前的前缀和等于当前前缀和减去 K。哈希表优化哈希表的设计我们使用哈希表来记录每个前缀和出现的次数。哈希表的键是前缀和的值值是该前缀和出现的次数。在遍历数组时对于每个位置我们首先计算当前的前缀和 current_sum。然后我们在哈希表中查找 key current_sum - K 的出现次数这个次数表示有多少个以当前位置结尾的和为 K 的子数组。def subarraySum(nums, k): prefix_sum 0 count 0 prefix_map {0: 1} for num in nums: prefix_sum num count prefix_map.get(prefix_sum - k, 0) prefix_map[prefix_sum] prefix_map.get(prefix_sum, 0) 1 return count初始化哈希表哈希表初始化为 {0: 1}表示前缀和为 0 出现了一次。这个初始化的作用是处理从数组开头开始的子数组。例如如果子数组 nums[0:j] 的和等于 K那么 prefixSum[j1] - prefixSum[0] K即 prefixSum[j1] K。由于我们初始化 prefixSum[0] 0在处理第一个元素时current_sum nums[0]我们需要检查 current_sum - K 是否等于 0即 K 是否等于 current_sum。如果没有初始化 {0: 1}这种情况就无法被正确计数。算法正确性证明数学归纳法我们使用数学归纳法证明算法的正确性。基例当处理第一个元素 nums[0] 时current_sum nums[0]。此时哈希表中只有 {0: 1}。如果 nums[0] K那么 prefix_sum - K 0 在哈希表中count 加上 1正确计数了子数组 nums[0:0]。如果 nums[0] ! Kcount 不变。基例成立。归纳假设假设在处理第 i 个元素之前哈希表正确记录了所有前缀和 prefixSum[0:i] 出现的次数count 正确计数了所有以第 i 个元素之前的位置结尾的和为 K 的子数组。归纳步骤处理第 i 个元素 nums[i] 后current_sum prefixSum[i1]。根据归纳假设此时 prefixSum[i] 已经在哈希表中。我们查找 prefix_sum - k prefixSum[i1] - K如果存在某个 j i1 使得 prefixSum[j] prefixSum[i1] - K那么子数组 nums[j:i1] 的和等于 prefixSum[i1] - prefixSum[j] K。因此将 prefix_map[prefix_sum - k] 加到 count 上正确计数了所有以 i 结尾的和为 K 的子数组。然后我们更新 prefix_map[current_sum]为后续的处理做准备。归纳步骤成立。复杂度分析时间复杂度时间复杂度为 O(n)因为我们只遍历数组一次每次迭代只进行常数次的哈希表操作查找和插入。空间复杂度空间复杂度为 O(n)在最坏情况下哈希表需要存储 n1 个不同的前缀和加上初始的 0。代码实现Python 实现def subarraySum(nums, k): prefix_sum 0 count 0 prefix_map {0: 1} for num in nums: prefix_sum num count prefix_map.get(prefix_sum - k, 0) prefix_map[prefix_sum] prefix_map.get(prefix_sum, 0) 1 return countJava 实现public int subarraySum(int[] nums, int k) { int prefixSum 0; int count 0; MapInteger, Integer prefixMap new HashMap(); prefixMap.put(0, 1); for (int num : nums) { prefixSum num; count prefixMap.getOrDefault(prefixSum - k, 0); prefixMap.put(prefixSum, prefixMap.getOrDefault(prefixSum, 0) 1); } return count; }边界情况处理空数组当数组为空时循环不会执行count 保持为 0返回 0符合预期。全负数数组算法同样适用于全负数数组。前缀和可以是负数哈希表的键可以是负数没有问题。全正数数组算法同样适用。对于全正数数组我们可以使用滑动窗口等其他方法但前缀和加哈希表的方法同样正确。K 为零当 K 0 时算法仍然有效。此时我们需要统计和为零的子数组数量。初始的 {0: 1} 会正确处理空前缀和。溢出问题在 Java 等语言中前缀和可能超出整数范围。由于 LeetCode 的测试用例通常在合理范围内且 Python 的整数可以自动扩展这个问题通常不需要特别处理。但在某些语言中可能需要使用 long 类型来存储前缀和。测试用例def test_subarray_sum(): assert subarraySum([1, 1, 1], 2) 2 assert subarraySum([1, 2, 3], 3) 2 assert subarraySum([1], 0) 0 assert subarraySum([0, 0], 0) 3 assert subarraySum([-1, -1, 1], 0) 1 assert subarraySum([1, 2, 3], 0) 0 print(所有测试用例通过)变种问题和至少为 K 的子数组如果问题改为统计和至少为 K 的子数组数量我们需要修改哈希表的查找逻辑。由于至少是一个范围查询不能简单地用哈希表解决。可以使用二分查找或滑动窗口等方法。乘积为 K 的子数组如果问题改为乘积为 K 的子数组需要使用对数变换将乘法转换为加法或者使用哈希表存储每个元素出现的次数适用于 K 包含较多因子的场景。和为 K 的最长子数组如果问题改为找到和为 K 的最长子数组的长度我们可以稍微修改算法在哈希表中存储每个前缀和首次出现的位置然后计算最长长度。实际应用场景和为 K 的子数组问题在现实中有很多应用。在金融领域可以用来检测连续交易日使累计收益达到特定值的情况。在信号处理中可以用来检测能量达到特定值的信号段。在数据分析中可以用来找出满足特定条件的数据段。前缀和加哈希表的方法是处理连续子数组统计问题的通用范式。掌握这个技巧后可以解决很多类似的问题。总结和为 K 的子数组问题展示了前缀和与哈希表结合的威力。通过将查找和为 K 的子数组转化为查找差值为 K 的两个前缀和我们可以在 O(n) 时间内解决看似需要 O(n²) 的问题。这个问题的关键洞察是子数组和等于 K 两个前缀和的差等于 K。通过哈希表快速查找满足条件的前缀和我们可以高效地统计所有符合条件的子数组。希望通过本文的讲解读者能够深入理解前缀和与哈希表结合的思想并将其应用到更多类似问题的解决中。

相关文章:

LeetCode 560:和为 K 的子数组 | 前缀和与哈希表

LeetCode 560:和为 K 的子数组 | 前缀和与哈希表 引言 和为 K 的子数组(Subarray Sum Equals K)是 LeetCode 第 560 题,难度为 Medium。题目要求在给定整数数组中找出连续子数组的元素和等于 K 的数量。这道题是前缀和与哈希表结合…...

前缀和与差分 | 数组区间查询的利器

前缀和与差分 | 数组区间查询的利器 引言 前缀和(Prefix Sum)与差分(Difference Array)是数组处理中两种重要且互补的技术。前缀和用于快速计算数组区间元素的和,而差分用于快速对数组区间进行相同的加减操作。这两种技…...

别再乱改注册表了!Windows系统文件夹移动后还原的完整避坑指南

Windows系统文件夹移动后还原的完整避坑指南1. 为什么你的文件夹移动操作会出问题?许多用户为了释放C盘空间,会选择将桌面、文档等系统文件夹移动到其他分区。这个看似简单的操作背后却隐藏着不少陷阱。最常见的错误是直接在目标盘符下选择移动&#xff…...

跨环境漏洞复现:Docker Desktop与VMware Kali的TCP/信号对齐实战

1. 这不是“复现个POC就完事”的演练,而是真实攻防链路上的环境卡点攻坚你有没有遇到过这种情况:在本地Kali虚拟机里跑通的CVE-2026-24061利用脚本,一放到客户现场的Docker Desktop环境里就报错——不是缺Python模块,就是socket连…...

Autumn Valley资源包:开放世界性能优化实战指南

1. 这个资源包不是“拿来就能跑”的美术资产,而是为开放世界性能瓶颈量身定制的解决方案我第一次在Unity Asset Store看到Autumn Valley - Level这个包时,下意识点开预览图——金黄的枫林、雾气缭绕的山谷、蜿蜒的碎石小径,画面确实抓人。但真…...

FPGA加速机器学习在粒子物理触发系统中的应用与实战

1. 项目概述:当FPGA遇上机器学习,为粒子物理装上“火眼金睛” 在大型强子对撞机(LHC)的心脏地带,每秒发生着数亿次质子对撞。每一次对撞都可能产生希格斯玻色子、顶夸克,或是我们尚未知晓的新物理现象。然而…...

SMGI框架:通用人工智能的结构元模型与实现路径解析

1. 项目概述:从“智能拼图”到“统一蓝图”最近几年,AI领域的热词层出不穷,从大语言模型到多模态,再到通用人工智能(AGI),大家似乎都在朝着同一个方向狂奔,但脚下的路却千差万别。这…...

反事实推理:用因果视角评估与缓解AI模型偏见

1. 项目概述:当模型决策需要“如果当初”在机器学习的世界里,我们常常面临一个困境:模型预测准确率很高,但我们却不知道它为什么做出这样的决策。更棘手的是,我们越来越频繁地发现,这些“黑箱”决策背后&am…...

基于FeFET的动态可重构FPGA:实现亚纳秒级上下文切换的硬件加速新架构

1. 项目概述与核心挑战如果你在硬件加速领域摸爬滚打过几年,大概率会对FPGA又爱又恨。爱的是它无与伦比的灵活性,恨的是它在“灵活”和“高效”之间那道难以逾越的鸿沟。传统基于SRAM的FPGA,其可重构性是通过烧写配置位流到SRAM单元来实现的。…...

Burp Suite扫描深度配置指南:被动扫描、主动扫描与自定义插入点协同调优

1. 这不是“点一下就扫完”的配置,而是扫描质量的分水岭 很多人把 Burp Suite Scanner 当成一个“自动漏洞探测器”——填个 URL,点下“Active Scan”,等它跑完弹出一堆高危告警,就以为任务完成了。我见过太多这样的场景&#xff…...

机器学习模型监控实战:KS检验与BC系数在大数据供应链预测中的应用

1. 项目概述:为什么模型上线后,监控比训练更重要?在机器学习项目里,我们常常把80%的精力花在数据清洗、特征工程和模型调优上,觉得模型一旦上线,任务就完成了。但真实的生产环境会给你上一课:一…...

安卓加固反调试核心机制:D-Bus监听与/proc/self/maps检测绕过实战

1. 这不是“绕过检测”,而是理解检测者如何思考你打开一个加固过的金融类App,Frida一挂上去,进程秒退;换上repack后的so,刚调用Java.perform就抛出SecurityException;甚至只是加载了frida-gadget.so&#x…...

Debian挂载NFS远程硬盘踩坑实录:权限拒绝、连接超时问题一站式解决

Debian挂载NFS远程硬盘踩坑实录:权限拒绝、连接超时问题一站式解决在Linux环境下使用NFS(Network File System)挂载远程存储是常见的跨服务器文件共享方案,但实际操作中常会遇到各种"拦路虎"。本文将以Debian系统为例&a…...

别再被GPG签名卡住了!手把手教你修复Kali老版本apt更新源报错

Kali Linux系统更新源管理进阶指南:从故障修复到高效运维当你成功解决了Kali Linux老版本因GPG签名失效导致的apt更新源报错后,这只是系统维护的第一步。真正的挑战在于如何构建一套可持续的运维策略,避免类似问题反复出现,同时提…...

除了Easy App Locker,还有哪些Mac应用加锁方案?横向对比与避坑指南

Mac应用加锁全方案评测:从系统原生到第三方工具的深度选择指南当你把Mac借给同事调试代码时,是否担心他们无意间看到你的通讯录或邮件?又或者家里的小朋友总想偷偷打开你的游戏客户端?应用加锁早已超越简单的隐私保护,…...

Unity PBR材质工作流:800个开箱即用的工业级材质球

1. 这不是“又一个免费资源包”,而是一套能直接进项目用的材质球工作流“Unity材质球资源集”这词儿听多了,点开链接——要么是30个基础金属塑料木头,要么是200个名字叫“Metal_Rough_01_v2_final_renamed”却连UV Tile都没调对的半成品。我去…...

边缘计算融合触觉互联网与数字孪生:构建超低延迟人机交互框架

1. 项目概述与核心价值最近几年,我一直在关注一个技术融合的交叉点:当边缘计算、触觉通信和数字孪生这三个看似独立的领域碰撞在一起时,会擦出什么样的火花?这个项目——“边缘计算赋能触觉互联网:构建沉浸式人机交互的…...

8051开发中禁用自动代码分区的实践指南

1. 禁用自动代码分区的技术背景在8051架构的嵌入式开发中,代码分区(Bank Switching)是一种扩展程序存储器空间的常用技术。传统8051芯片的寻址空间有限,通过分区切换机制可以将代码分布到不同的物理存储区域。Keil C51开发工具链默…...

从零到一:用 LangChain 搭建你的第一个 AI Agent,让 LLM 自己干活!

导读:,2024年最火的不是大模型本身,而是基于大模型的 AI Agent。它能自主思考、调用工具、执行任务——不再是"你说一句我回一句"的聊天机器人,而是真正能帮你干活的数字员工。本文从零带你搭建一个完整的 AI Agent&…...

Arm Development Studio许可协议核心条款与合规指南

1. Arm Development Studio 终端用户许可协议解析作为一名长期从事嵌入式开发的工程师,我深知开发工具许可协议的重要性。Arm Development Studio 作为业界领先的嵌入式开发套件,其 EULA(终端用户许可协议)直接影响着我们的日常开…...

AI加速器硬件安全防护技术与实践

1. AI加速器的硬件安全威胁与防护需求在数据中心和边缘计算场景中,AI加速器已成为支撑人工智能工作负载的核心基础设施。这些高性能计算设备通常运行着价值连城的专有算法和训练数据,其物理安全直接关系到企业的核心资产保护。与传统服务器不同&#xff…...

C51嵌入式开发中的栈下溢检测与实现

1. C51运行时栈下溢检测原理与实现在嵌入式C51开发中,栈空间管理是个永恒的话题。我曾在一个智能电表项目中,因为栈溢出导致系统随机崩溃,花了整整两周时间才定位到问题。从那以后,我养成了在关键项目中实现运行时栈检查的习惯。栈…...

FPGA在材料测试中的高精度控制与并行处理应用

1. FPGA在材料测试领域的革新价值 材料测试设备作为工业质量控制的核心装备,其性能直接影响着从汽车安全气囊到医疗植入物的产品可靠性。传统基于通用微控制器的测试系统正面临三大技术瓶颈:首先是测试标准迭代速度快,ASTM、ISO等组织每年新增…...

用格拉姆矩阵特征值调整替代SVD,高效求解带正交约束的优化问题

1. 项目概述与核心问题在机器学习和数值优化的世界里,我们经常遇到一个经典难题:如何在一个带约束的复杂空间里,找到那个“最好”的解。这就像在一个布满规则的迷宫里寻找宝藏,你不能横冲直撞,必须遵守墙壁&#xff08…...

机器学习势函数在氧化镓多晶型相变模拟中的应用与验证

1. 项目概述与核心挑战氧化镓(Ga2O3)作为下一代宽禁带半导体的明星材料,这几年在功率电子和深紫外光电器件领域的热度一直居高不下。它的优势很明显:超宽的禁带宽度(4.8-5.3 eV)、极高的临界击穿电场&#…...

机器学习赋能智能建筑:从能耗预测到个性化舒适度优化

1. 项目概述:当机器学习遇见智能建筑如果你在写字楼里工作,大概率经历过这样的场景:夏天,靠近空调出风口的同事裹着毯子瑟瑟发抖,而角落里的同事却在默默擦汗;冬天,会议室里有人喊热要开窗&…...

大数据供应链预测模型监控:KS检验与Bhattacharyya系数的工程实践

1. 项目概述在供应链预测这类高价值、高风险的机器学习应用里,最让人提心吊胆的时刻,往往不是模型训练,而是它上线之后。我们精心调校的模型,就像一个被派往复杂前线的侦察兵,训练时用的是一套“地图”(历史…...

微生物代谢建模与计算机视觉特征匹配技术解析

1. 微生物代谢建模中的协同设计1.1 工业生物技术中的代谢网络基础微生物代谢网络是细胞内酶催化化学反应的综合体系,不同物种间存在显著差异。在工业生物技术领域,这些网络能将废物流等原料转化为高附加值产品。以丁酸梭菌(Clostridium butyr…...

BU-CVKit:模块化计算机视觉框架赋能跨物种动物行为分析

1. 项目概述:从实验室到旷野,一个框架的野心在计算机视觉研究领域,尤其是动物行为学和生态学方向,我们常常面临一个尴尬的局面:针对小鼠开发的追踪算法,拿到斑马鱼身上就水土不服;为猕猴设计的姿…...

CoQMoE:面向FPGA的MoE-ViT量化与硬件协同设计实践

1. 项目概述:当视觉Transformer遇上FPGA,为何需要“协同设计”?最近几年,视觉Transformer(ViT)在图像识别、目标检测等任务上展现出了不输甚至超越传统卷积神经网络(CNN)的性能。但随…...