LeetCode算法刷题——560. 和为 K 的子数组

一、题目描述

二、解题思路

使用前缀和 + 哈希表的方法来高效解决这个问题:

  1. 计算到每个位置的前缀和(当前位置之前所有元素的和)

  2. 对于当前前缀和 presum(i),如果存在某个之前的前缀和presum(j),满足presum(i)- presum(j)= k, 那么从那个位置到当前位置的子数组和就是k

  3. 变换一下公式,得到presum(i)- k= presum(j),我们发现只要有一个此之前的前缀和等于当前前缀和减去k,那么就有一个符合的要求的字串

  4. 重要思想:使用哈希表,k记录前缀和,v记录每个前缀和出现的次数

  5. 注意:初始化时,前缀和为0出现了1次(表示数组开始前的情况)

三、完整代码

class Solution {

public:

int subarraySum(vector<int>& nums, int k) {

unordered_map<int, int> mp; // 哈希表:key=前缀和, value=出现次数

mp[0] = 1; // 前缀和为0出现1次

int sum = 0; // 当前前缀和

int count = 0; // 符合条件的子数组个数

for(int i = 0; i < size(nums); i++) {

sum = sum + nums[i]; // 更新前缀和

if(mp.count(sum - k)) { // 检查是否存在sum-k的前缀和

count = count + mp[sum - k]; // 加上出现的次数

}

mp[sum]++; // 更新当前前缀和的出现次数

}

return count;

}

};

四、代码解析

1. 哈希表初始化

map<int, int> mp;

mp[0] = 1;

  • 关键:map[0]=1表示前缀和为0的情况出现了1次

  • 情况1:对于从数组开头开始的子数组等于k的情况

    • k=3 nums=【2,1,4,-1】
  • 情况2:对于子串元素数为1的情况

    • k=3,nums=【1,4,-2,3,6】

2. 前缀和计算

sum = sum + nums[i];

  • 累加当前元素,得到从数组开头到当前位置的总和

  • 这个值表示前 i+1 个元素的和

3. 查找符合条件的子数组

if(mp.count(sum - k)) {

count = count + mp[sum - k];

}

  • 核心逻辑:如果存在之前的前缀和等于 sum - k (当前的前缀和-目标k)

  • 那么相减获得的子数组和就是 k

  • 可能有多个位置的前缀和相同,所以要加上出现的次数

4. 更新哈希表

mp[sum]++;

  • 将当前前缀和的出现次数加1

  • 这个操作要在检查之后进行,避免使用当前自身的前缀和

五、语法要点

1. 为什么不先整体计算前缀和再处理?

如果先建完整的哈希表,在统计时无法区分前缀和是在当前位置之前还是之后

2. 为什么使用 map<前缀和, 频次> 而不是 map<索引, 前缀和>

(1)快速查找需求

  • 我们需要快速知道:是否存在某个前缀和等于 当前前缀和 - k

  • 使用 map<前缀和, 频次>mp.count(sum - k) 是 O(1) 查找

  • 使用 map<索引, 前缀和>:需要遍历所有索引才能找到特定前缀和,效率低

(2)计数需求:

  • 使用频次可以准确统计所有可能性

  • 例如:nums = [1, -1, 1, -1, 1],前缀和为1的位置可能有多个

  • 同一前缀和可能出现在多个位置(如数组中有0或正负抵消的情况)

六、执行示例

输入:nums = [1,1,1], k = 2

执行过程:

  1. 初始化:mp = {0:1}, sum=0, count=0

  2. i=0: sum=1,检查 1-2=-1 不存在 → mp[1]=1mp={0:1, 1:1}

  3. i=1: sum=2,检查 2-2=0 存在 → count+=mp[0]=1mp[2]=1mp={0:1, 1:1, 2:1}

  4. i=2: sum=3,检查 3-2=1 存在 → count+=mp[1]=2mp[3]=1mp={0:1, 1:1, 2:1, 3:1}

最终结果:2

对应子数组:

  • 索引 [0,1]:nums[0]+nums[1] = 1+1 = 2

  • 索引 [1,2]:nums[1]+nums[2] = 1+1 = 2

七、总结

本文介绍了使用前缀和和哈希表统计和为k的子数组个数的高效算法。该算法的核心在于将问题转化为寻找两个前缀和之差等于k的情况。通过维护一个哈希表记录每个前缀和出现的次数,我们可以在O(n)时间复杂度内解决问题。这种方法特别适用于包含负数的数组,而滑动窗口法只适用于全正数的情况。关键点包括:正确初始化mp[0]=1、理解sum-k的含义、以及及时更新前缀和的出现次数。

相关推荐
水水不水啊1 小时前
通过一个域名,借助IPV6免费远程访问自己家里的设备
前端·python·算法
.格子衫.1 小时前
027动态规划之矩阵DP——算法备赛
算法·矩阵·动态规划
wdfk_prog1 小时前
[Linux]学习笔记系列 -- [block]kyber-iosched
linux·笔记·学习
nju_spy1 小时前
力扣每日一题(11.10-11.29)0-1 和 k 整除系列
python·算法·leetcode·前缀和·单调栈·最大公约数·0-1背包
roman_日积跬步-终至千里1 小时前
【模式识别与机器学习(8)】主要算法与技术(下篇:高级模型与集成方法)之 元学习
学习·算法·机器学习
haing20191 小时前
Bezier曲线曲率极值的计算方法
人工智能·算法·机器学习·曲率极值
大志若愚YYZ1 小时前
嵌入式Linux学习——Framebuffer 应用编程详解(理论知识)
学习
嵌入式小能手1 小时前
飞凌嵌入式ElfBoard-文件I/O的深入学习之阻塞I/O与非阻塞I/O
学习
歌_顿1 小时前
深度学习算法以及优化器复习
人工智能·算法