1. 问题描述:
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
- 数组的长度为 [1, 20,000]。
- 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
2. 思路分析:
① 一开始比较容易想到的是暴力破解,依次从当前位置开始的区间[i, j]累加求和,判断是否等于k,假如等于了k那么对子数组的计数加1,最后返回结果即可,很明显代码的时间复杂度为O(n ^ 2),我们需要累加求解所有的区间的和才可以得到最终的结果,提交上去是超时的
② 第二个思路是前缀和,我们可以遍历nums数组,得到从0到当前位置i的和,然后依次检查每一个区间的和:prefix[j] - prefix[i] 是否等于k,假如等于了k那么计数加1,最终将结果返回,但是其实这个解法比暴力破解还需更费时一点,因为在计算每一个区间和的时候还多遍历了一次nums数组,所以还不如暴力破解
③ 第三个解法是在力扣的题解上看到的,使用的哈希表的思路来解决的(感觉有点类似于动态规划的意思),对于python语言来说可以使用字典来实现,感觉这个思路比较巧妙一点,而且不容易想到吧,下面是我对力扣题解中哈希表思路的理解:
需要借助于一个变量来累加从0到当前位置的和,这个和就代表了0到当前位置的这个区间的和,遍历nums数组,检查sum - k中是否存在于字典中,为什么要这样检查呢?主要是因为0-i为当前这个区间,sum表示的是0-i这个区间上的总和,而sum - k表示的是前面是否存在0-j这个区间的和等于sum - k呢假如存在了说明以当前的数字结尾的数字往前的若干个数字的总和是等于k的,说起来感觉很绕,其实借助于pycharm的debug调试 + 简单的测试数据就可以理解这个思略了
测试数据:
nums = [2, 1, 2, 1, 2, 3, 4, 2, 1], k = 5
3. 代码如下:
字典:
from typing import List
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
dic, res, sum = {0: 1}, 0, 0
for i in nums:
sum += i
t = sum - k
res += dic.get(t, 0)
dic[sum] = dic.get(sum, 0) + 1
return res
前缀和:
from typing import List
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
# 下面采用的前缀和的方式来进行实现的
length = len(nums)
prefixSum = [0] * (length + 1)
for i in range(length):
prefixSum[i + 1] = prefixSum[i] + nums[i]
res = 0
for r in range(length + 1):
for l in range(0, r):
if prefixSum[r] - prefixSum[l] == k:
res += 1
return res
暴力破解:
from typing import List
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
res = 0
for i in range(len(nums)):
sum = 0
for j in range(i, len(nums)):
sum += nums[j]
if sum == k:
res += 1
return res