给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
数组的长度为 [1, 20,000]。 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
- 该题主要是使用了前缀和的思想。前缀和,顾名思义即对所有
i∈[0, n-1]
,统计数组中0~i个元素之和。那么,则可通过解num[i:j] = num[0:j] - num[0:i]
,对num[i:j]=k
的求解。即,将问题转化为挑选一对前缀和,比二者之差是否与k相等。 - 由上可知,可求一个前缀和数组,并通过暴力法穷举得到答案。但时间复杂度为$O(n^2)$
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cnt, n = 0, len(nums)
pre = [0] * (n + 1)
for i in range(1, n + 1):
pre[i] = pre[i - 1] + nums[i - 1]
for i in range(1, n + 1):
for j in range(i, n + 1):
if (pre[j] - pre[i - 1] == k): cnt += 1
return cnt
- 因此,可使用哈希表来进行优化。使用哈希表存储某数值(前缀和key)与该值对应的组合数量(value)之间的映射。那么,若$current=k$,则结果+1;若当前前缀和$current-k$(将current理解为
num[0:j]
)在该哈希表中,说明可以找到sum2cnt[current-k]
个num[0:i]
符合题目要求。
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
current, cnt = 0, 0
sum2cnt = {} # 记录前缀和与对应数量的映射
for i in nums:
current += i
if current == k:
cnt += 1
if current - k in sum2cnt:
cnt += sum2cnt[current-k]
if current in sum2cnt:
sum2cnt[current] += 1
else:
sum2cnt[current] = 1
return cnt