【LeetCode刷题】和为K的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。
示例 1:
输入:nums = [1,1,1], k = 2 输出:2
示例 2:
输入:nums = [1,2,3], k = 3 输出:2
提示:
1 <= nums.length <= 2 *-1000 <= nums[i] <= 1000-107 <= k <=
解题思路:
1. 用前缀和表示子数组和
定义前缀和 pre_sum 为数组前 i 个元素的累计和(即 pre_sum[i] = nums[0] + nums[1] + ... + nums[i-1])。对于任意子数组 nums[j..i](从索引 j 到 i 的连续元素,0 ≤ j ≤ i < n),其和可表示为:子数组和 = pre_sum[i+1] - pre_sum[j]
若该子数组和等于 k,则有:pre_sum[i+1] - pre_sum[j] = k → pre_sum[j] = pre_sum[i+1] - k
因此,问题转化为:对于每个前缀和 pre_sum[i],统计有多少个之前的前缀和 pre_sum[j] 等于 pre_sum[i] - k,这些 j 对应的子数组 nums[j..i-1] 的和即为 k。
2.记录前缀和出现次数
为了快速统计 “等于 pre_sum[i] - k 的前缀和” 的个数,使用哈希表 hash_map 存储前缀和的值与该值出现的次数的映射。
初始状态:
hash_map[0] = 1这是为了处理 “子数组从索引 0 开始” 的特殊情况。例如,若pre_sum[i] = k,则pre_sum[i] - k = 0,此时需要统计到初始的pre_sum=0(对应j=0)。遍历过程:遍历数组时,不断更新当前前缀和
pre_sum,并检查pre_sum - k是否在哈希表中:- 若存在,说明有
hash_map[pre_sum - k]个符合条件的子数组,将其累加到结果count中; - 然后将当前前缀和
pre_sum存入哈希表(次数加 1),供后续遍历使用。
- 若存在,说明有
时间与空间复杂度分析:
- 时间复杂度:
O(n)(n为数组长度)。仅需遍历数组一次,哈希表的插入和查询操作均为O(1)。 - 空间复杂度:
O(n)。哈希表最多存储n个不同的前缀和(极端情况下所有前缀和均不重复)。
示例说明(以 nums = [1,1,1], k = 2 为例):
- 初始:
pre_sum = 0,hash_map = {0:1},count = 0。 - 遍历第 1 个元素
1:pre_sum = 0 + 1 = 1,pre_sum - k = -1(不在哈希表),count不变。更新哈希表:hash_map[1] = 1。 - 遍历第 2 个元素
1:pre_sum = 1 + 1 = 2,pre_sum - k = 0(在哈希表,次数 1),count += 1(此时count=1)。更新哈希表:hash_map[2] = 1。 - 遍历第 3 个元素
1:pre_sum = 2 + 1 = 3,pre_sum - k = 1(在哈希表,次数 1),count += 1(此时count=2)。更新哈希表:hash_map[3] = 1。 - 最终返回
count=2,符合示例结果。
Python代码:
from typing import List
from collections import defaultdictclass Solution:def subarraySum(self, nums: List[int], k: int) -> int:pre_sum = 0count = 0# 哈希表记录前缀和及其出现次数,初始前缀和0出现1次hash_map = defaultdict(int)hash_map[0] = 1for num in nums:pre_sum += num# 若pre_sum - k存在于哈希表,说明存在子数组和为kif pre_sum - k in hash_map:count += hash_map[pre_sum - k]# 更新当前前缀和的出现次数hash_map[pre_sum] += 1return countif __name__ == "__main__":# 处理输入(格式如:nums = [1,1,1], k = 2)import renums_input = input().strip()k_input = input().strip()nums = list(map(int, re.search(r'\[.*?\]', nums_input).group().strip('[]').split(',')))k = int(re.search(r'\d+', k_input).group())solution = Solution()result = solution.subarraySum(nums, k)print(result)
LeetCode提交代码:
class Solution:from typing import Listfrom collections import defaultdictdef subarraySum(self, nums: List[int], k: int) -> int:pre_sum = 0count = 0# 哈希表记录前缀和及其出现次数,初始前缀和0出现1次hash_map = defaultdict(int)hash_map[0] = 1for num in nums:pre_sum += num# 若pre_sum - k存在于哈希表,说明存在子数组和为kif pre_sum - k in hash_map:count += hash_map[pre_sum - k]# 更新当前前缀和的出现次数hash_map[pre_sum] += 1return count程序运行结果如下:

总结
本文介绍了如何统计数组中连续子数组和等于给定整数k的个数。通过使用前缀和与哈希表技术,将问题转化为查找满足pre_sum[j] = pre_sum[i]-k的前缀和出现次数。算法时间复杂度O(n),空间复杂度O(n)。示例演示了该方法的计算过程,并提供了Python实现代码,可处理输入格式如nums=[1,1,1],k=2的情况。这种方法高效地解决了子数组和统计问题。
