您可以跟踪起点(索引)和从该起点开始的累积总和。每次您的累积总和达到或超过目标时,您将起点向前移动,减去旧值,直到总和回到目标以下。在这个过程中,每次累积和等于目标时,你就有了一个可以计数的合格子串。
但是,除非我们考虑到零的影响,否则这将无法完美运行。例如,当我们到达 [0,4,0,3,1,0,1,0,1] 时,最后的 1 使和大于 9,所以我们移动起始位置得到 [4,0,3 ,1,0,1,0,1] 但这仍然大于 9,因为我们已经通过了倒数第二个零,因此将跳过两个有效的子范围。 [4,0,3,1,0,1,0] 和 [4,0,3,1,0,1]。为了在保持线性性能的同时解决这个问题,我们需要在将最后一项添加到总和之前执行范围缩小,并在总和与目标匹配时为每个尾随零计算一个额外的子范围。
S = '3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2'
target = 9
N = list(map(int,S.split(',')))
start = 0
cumSum = 0
count = 0
for end,value in enumerate(N+[target+1]): # force out ending subranges
while cumSum+value>target and start<end:
cumSum -= N[start] # shrink range
start += 1
if cumSum==target: # count matches (+extra for trailing zeroes)
count += next((c for c,v in enumerate(N[end-1:start:-1],1) if v),1)
cumSum += value # extend range
count += cumSum==target # count matches
print(count) # 7
如果您想确切知道哪些子字符串产生了目标总和,您可以稍微更改循环以将它们打印出来并证明它有效:
S = '3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2'
target = 9
N = list(map(int,S.split(',')))
start = 0
cumSum = 0
count = 0
for end,value in enumerate(N+[target+1]): # force out ending subranges
while cumSum+value>target and start<end:
cumSum -= N[start] # shrink range
start += 1
if cumSum==target: # count matches (+extra for trailing zeroes)
c = next((c for c,v in enumerate(N[end-1:start:-1],1) if v),1)
print([start,end],N[start:end],f"Matches {c}")
cumSum += value # extend range
if cumSum==target:
print([start,end+1],N[start:end+1],"Matches 1")
[1, 8] [0, 4, 0, 3, 1, 0, 1] Matches 1
[1, 9] [0, 4, 0, 3, 1, 0, 1, 0] Matches 1
[2, 9] [4, 0, 3, 1, 0, 1, 0] Matches 2
[10, 15] [0, 0, 5, 0, 4] Matches 1
[11, 15] [0, 5, 0, 4] Matches 1
[12, 15] [5, 0, 4] Matches 1