0560. 和为 K 的子数组
大约 3 分钟
0560. 和为 K 的子数组
- 标签:数组、哈希表、前缀和
- 难度:中等
题目链接
题目大意
描述:给定一个整数数组 和一个整数 。
要求:找到该数组中和为 的连续子数组的个数。
说明:
- 。
- 。 。
示例:
- 示例 1:
输入:nums = [1,1,1], k = 2
输出:2
- 示例 2:
输入:nums = [1,2,3], k = 3
输出:2
解题思路
思路 1:枚举算法(超时)
先考虑暴力做法,外层两重循环,遍历所有连续子数组,然后最内层再计算一下子数组的和。部分代码如下:
for i in range(len(nums)):
for j in range(i + 1):
sum = countSum(i, j)
这样下来时间复杂度就是 了。下一步是想办法降低时间复杂度。
对于以 开头,以 结尾()的子数组 来说,我们可以通过顺序遍历 ,逆序遍历 的方式(或者前缀和的方式),从而在 的时间复杂度内计算出子数组的和,同时使用变量 统计出和为 的子数组个数。
但这样提交上去超时了。
思路 1:代码
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cnt = 0
for j in range(len(nums)):
sum = 0
for i in range(j, -1, -1):
sum += nums[i]
if sum == k:
cnt += 1
return cnt
思路 1:复杂度分析
- 时间复杂度:。
- 空间复杂度:。
思路 2:前缀和 + 哈希表
先用一重循环遍历数组,计算出数组 中前 个元素的和(前缀和),保存到一维数组 中,那么对于任意 的子数组的和为 。这样计算子数组和的时间复杂度降为了 。总体时间复杂度为 。
但是还是超时了。。
由于我们只关心和为 出现的次数,不关心具体的解,可以使用哈希表来加速运算。
的定义是前 个元素和,则 可以由 递推而来,即:。 子数组和为 可以转换为:。
综合一下,可得:$pre\underline{\hspace{0.5em}}sum[i - 1] == pre\underline{\hspace{0.5em}}sum[j] - k $。
所以,当我们考虑以 结尾和为 的连续子数组个数时,只需要统计有多少个前缀和为 (即 )的个数即可。具体做法如下:
- 使用 变量记录前缀和(代表 )。
- 使用哈希表 记录 出现的次数。键值对为 。
- 从左到右遍历数组,计算当前前缀和 。
- 如果 在哈希表中,则答案个数累加上 。
- 如果 在哈希表中,则前缀和个数累加 ,即 。
- 最后输出答案个数。
思路 2:代码
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
pre_dic = {0: 1}
pre_sum = 0
count = 0
for num in nums:
pre_sum += num
if pre_sum - k in pre_dic:
count += pre_dic[pre_sum - k]
if pre_sum in pre_dic:
pre_dic[pre_sum] += 1
else:
pre_dic[pre_sum] = 1
return count
思路 2:复杂度分析
- 时间复杂度:。
- 空间复杂度:。