前缀和方式的代码, 时间复杂度为o( n** 2 )
是无法通过测试用例的
def fun1 ( nums, goal) :
count= 0
dp= [ 0 ]
for i in nums:
dp. append( dp[ - 1 ] + i)
for i in range ( 1 , len ( dp) ) :
for j in range ( i, len ( dp) ) :
if dp[ j] - dp[ i- 1 ] == goal:
count+= 1
elif dp[ j] - dp[ i- 1 ] > goal:
break
return count
print ( fun1( [ 1 , 0 , 1 , 0 , 1 ] , 2 ) )
可以采取更为简单的方法, 滑动窗口
不断地进入窗口, 当对应的数值大于目标值时 left往右移动
当对应数值小于等于目标值时right向右移动
该滑动窗口的思路有问题, 想的过于简单了
def fun2 ( nums, goal) :
left= 0
right= 0
count= 0
hdck= nums[ left]
while left< len ( nums) :
if hdck> goal:
left+= 1
hdck-= nums[ left- 1 ]
else :
if hdck== goal:
count+= 1
if right< len ( nums) - 1 :
right+= 1
hdck += nums[ right]
else :
left+= 1
hdck -= nums[ left - 1 ]
return count
print ( fun2( [ 1 , 0 , 1 , 0 , 1 ] , 2 ) )
正确的思路:
( 个人认为这个方法不好理解
s1, s2用来记录l1, l2到r的和( 左闭右闭形式)
l1记录的是第一个sums[ j] - sums[ l1- 1 ] ( l1到r) 小于goal
l2记录的是第一个sums[ j] - sums[ l2- 1 ] ( l2到r) 等于goal
应该是因为步长为0 , 1 的原因
这样l1- l2就是对于r所有可能的结果
def fun4 ( nums, goal) :
s1 = 0
s2 = 0
l1 = 0
l2 = 0
r = 0
res = 0
while r < len ( nums) :
s1 += nums[ r]
s2 += nums[ r]
while l1 <= r and s1 >= goal:
s1 -= nums[ l1]
l1 += 1
while l2 <= r and s2 > goal:
s2 -= nums[ l2]
l2 += 1
res += l1 - l2
r += 1
return res
前缀和+ 哈希表的方法
对于一个前缀和, 通过哈希表进行 sums- goal判断
这样就可以得到在 i到j区间内有多少个可行解
可以吧算法优化到o( n)
这里要注意res+= select. get( sum_- goal, 0 )
如果为0 , 则说明其自己是可以加入进去的, 这就要看有几个0 了( 自身以及其他可能为0 的前缀和)
def fun3 ( nums, goal) :
select= { }
sum_= 0
res= 0
for i in range ( len ( nums) ) :
select[ sum_] = select. get( sum_, 0 ) + 1
sum_+= nums[ i]
res+= select. get( sum_- goal, 0 )
return res