时间复杂度:O(n),空间复杂度:O(n)
解题思路
解该题的核心为前缀和。
什么是前缀和呢?我们可以理解为数组中前i个元素的和。那么为什么该题要用到前缀和以及该如何使用呢?
我们发现,前i个元素的前缀和记为preI,前j个元素的前缀和记为preJ,假设[i,j]区间内的元素和为K,那么就会得到一个式子:
preI+K=preJ,即preI=preJ-K
这时我们就会发现,如果令preJ-K的值固定,满足式子的preI出现几次就说明有几个[i,j]的区间满足元素和为K。这样我们就可以通过一遍遍历数组记录下所有的前缀和及其出现的次数,当遍历到nums[j]时,如果已经记录的前缀和有nums[i]满足nums[i]=nums[j]-K的,那么就让结果res加上前缀和nums[i]出现的次数。
既然我们想要迅速查找是否有满足条件的nums[i],且需要记录它出现的次数,那么最好的存储结构就是哈希表。令哈希表的key为前缀和,值为该前缀和出现的次数,这样就可以将时间复杂度降为O(n)。
AC代码
func subarraySum(nums []int, k int) (res int) {
m:=map[int]int{}//key为前缀和,值为出现次数
pre:=0//前缀和
m[0]=1//初始条件
for _,num:=range nums{
pre+=num
if count,ok:=m[pre-k];ok{
res+=count
}
m[pre]++//最后再记录当前前缀和,否则遇到0会出错
}
return res
}
感悟
一开始想用动态规划的方法去做,做了十分钟总感觉不对。看了官方题解十分钟才明白说的是个什么解法……