python 和为k的字数组(子串-中等)含源码 (一)
问题说明(含示例)
问题描述:给定一个整数数组 nums 和一个整数 k,请统计并返回该数组中和为 k 的连续子数组的个数。其中,子数组是数组中元素的连续非空序列。
示例:
-
输入:
nums = [1,1,1],k = 2输出:2解释:和为 2 的连续子数组有两个,分别是[1,1](索引 0-1)和[1,1](索引 1-2)。 -
输入:
nums = [1,2,3],k = 3输出:2解释:和为 3 的连续子数组有两个,分别是[1,2](索引 0-1)和[3](索引 2)。
解题关键
本题的核心解法是 “前缀和 + 哈希表”,通过将子数组和的问题转化为前缀和的差值问题,大幅降低时间复杂度,具体逻辑如下:
-
前缀和定义:设
sum_count[i]为数组nums前i个元素的累加和(即sum_count[i] = nums[0] + nums[1] + ... + nums[i-1])。例如,sum_count[0] = 0(前 0 个元素和为 0),sum_count[1] = nums[0],sum_count[2] = nums[0] + nums[1]。 -
核心关系推导:对于任意连续子数组
nums[j..i-1](索引从j到i-1,长度为i-j),其和为:sum(nums[j..i-1]) = sum_count[i] - sum_count[j]。若该子数组和为k,则满足sum_count[i] - sum_count[j] = k,变形可得sum_count[j] = sum_count[i] - k。 -
问题转化:统计 “和为
k的子数组个数”,等价于统计 “对于每个i,前缀和sum_count[j] = sum_count[i] - k出现的总次数”。即遍历过程中,每计算一个当前前缀和sum_count[i],查询哈希表中sum_count[i] - k的出现次数,累加该次数即为结果。 -
边界处理:初始化哈希表
pre_count = {0: 1},表示 “前缀和为 0 出现过 1 次”。这是为了处理 “当前前缀和sum_count[i]本身等于k” 的情况(此时sum_count[i] - k = 0,需统计这 1 次)。
对应代码
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
# 哈希表:key=前缀和,value=该前缀和出现的次数;初始{0:1}处理边界(前缀和直接等于k的情况)
pre_count = {0: 1}
sum_count = 0 # 记录当前的前缀和(前i个元素的累加和)
result = 0 # 记录和为k的子数组个数
# 遍历数组,逐个更新前缀和并统计结果
for num in nums:
sum_count += num # 累加当前元素,得到新的前缀和
# 若sum_count - k在哈希表中,说明存在对应的sum_count[j],累加其出现次数
if sum_count - k in pre_count:
result += pre_count[sum_count - k]
# 更新哈希表:当前前缀和的出现次数+1;若不存在则默认0+1
pre_count[sum_count] = pre_count.get(sum_count, 0) + 1
return result
对应的基础知识
实现该算法需掌握以下 Python 基础语法与操作:
-
字典(哈希表)的核心操作
- 初始化:
pre_count = {0: 1}创建键值对字典,用于存储前缀和与对应出现次数; get()方法:pre_count.get(sum_count, 0)尝试获取键sum_count对应的值,若键不存在则返回默认值 0(避免 KeyError);- 键值对更新:
pre_count[sum_count] = ...为字典添加或修改键sum_count对应的 value(更新前缀和出现次数)。
- 初始化:
-
前缀和的计算通过变量
sum_count累加遍历到的每个num,动态维护 “当前前缀和”(前i个元素的和),无需额外存储所有前缀和(节省空间)。 -
for 循环遍历
for num in nums直接迭代数组元素,逐个处理每个元素对前缀和的贡献,逻辑直观且避免索引越界。 -
条件判断与累加
if sum_count - k in pre_count判断 “目标前缀和” 是否存在,存在则将其出现次数累加到result,实现子数组个数的统计。 -
变量初始化
sum_count = 0:初始前缀和为 0(前 0 个元素的和);result = 0:初始统计结果为 0,随遍历逐步累加。
对应的进阶知识
该问题的解决涉及算法设计与复杂度优化的进阶思想:
-
前缀和思想的本质前缀和将 “子数组和” 的计算转化为 “两个前缀和的差值”,避免了暴力法中 “枚举所有子数组并计算和” 的冗余操作(暴力法需嵌套循环,时间复杂度
O(n²))。 -
哈希表的优化作用哈希表的核心价值是 O (1) 时间复杂度的查询与更新:
- 暴力法中,判断是否存在
sum_count[j] = sum_count[i] - k需遍历所有历史前缀和(O(n)时间); - 用哈希表存储前缀和出现次数后,查询和更新均为
O(1),总时间复杂度降至O(n)(仅遍历数组一次)。
- 暴力法中,判断是否存在
-
边界处理的必要性初始化
pre_count = {0: 1}是算法正确性的关键:- 当遍历到第一个元素
num = k时,sum_count = k,此时sum_count - k = 0,若哈希表无0:1,则会遗漏 “子数组[num]和为 k” 的情况; - 该初始化本质是 “默认前缀和 0 出现过 1 次”,覆盖了 “前缀和直接等于 k” 的边界场景。
- 当遍历到第一个元素
-
复杂度分析
- 时间复杂度:
O(n),n为数组长度,仅遍历数组一次,哈希表操作均为O(1); - 空间复杂度:
O(n),哈希表最多存储n+1个不同的前缀和(若所有前缀和均不重复,如数组元素全为正数时)。
- 时间复杂度:
-
与暴力法的对比暴力法通过嵌套循环枚举所有子数组(外层循环定起点,内层循环定终点,计算子数组和),时间复杂度
O(n²),在n较大时(如n=10^4)会超时;而 “前缀和 + 哈希表” 解法通过空间换时间,将时间复杂度优化至O(n),是处理大规模数组的最优方案。
更多推荐
所有评论(0)