计算给定总和为零的所有连续子数组
Posted
技术标签:
【中文标题】计算给定总和为零的所有连续子数组【英文标题】:Counting all contiguous sub-arrays given sum zero 【发布时间】:2014-12-19 09:28:15 【问题描述】:给定长度为 n 的随机数(正数和负数)数组,我想要总和为零的连续子数组。
示例:
假设我有数组a=1, -1 ,2 , -2, 6, -6
,输出将是6
,因为子数组如下:
1 -1 & 2 -2 & 6 -6 & 1 -1 2 -2 & 2 -2 6 -6 & 1 -1 2 -2 6 -6
我知道强力解 O(n^2),我想要任何其他解 O(n) 或 O(n log n)?
【问题讨论】:
我不认为contiguous sub-arrays sum
问题有O(n), or O(n log n)
解决方案..
由于可能的子数组的总数是 O(n^2),我怀疑你会想出一个比这更好的通用算法。如果你这样做,它必须是一种不仅仅枚举子数组的方法。考虑这个困难的情况:6,0,0,...0,0,-6。
考虑 0, 0, ... 0, 0 ,现在所有的总和都为零,你必须输出很多东西。
仅供参考:我认为@DavidEisenstat 证明我错了,如下。
【参考方案1】:
设数组为 a1, ..., an。令 s0, ..., sn 为 sj = a1 + ... + aj 定义的前缀和(并且 s0 = 0)。从 i 到 j 的子数组的和是 sj - si-1。对于 O(n)/O(n log n) 时间算法,使用映射计算前缀和中每个数字的出现次数。求和 k 为这张地图的值中的 k 选择 2。
例如,如果我们有你的数组
1 -1 2 -2 6 -6
那么前缀和是
0 1 0 2 0 6 0
计数是
0: 4
1: 1
2: 1
3: 1
输出是 4 选择 2 + 1 选择 2 + 1 选择 2 + 1 选择 2 = 6(其中 k 选择 2 = k(k-1)/2)。
在 Python 中:
def countsumzero(lst):
prefixsums = [0]
for x in lst:
prefixsums.append(prefixsums[-1] + x)
freq =
for y in prefixsums:
if y in freq:
freq[y] += 1
else:
freq[y] = 1
return sum(v*(v-1) // 2 for v in freq.values())
【讨论】:
+1:哇,太好了!我认为没有办法将它们全部列举出来,但这似乎确实有效。 我不明白得到前缀和之后的下一步是什么? @DavidEisenstat 我不明白 sum(v*(v-1) // 2 for v in freq.values()) 背后的原因 一切正常。但是最后一行是什么“输出是 4 选择 2 + 1 选择 2 + 1 选择 2 + 1 选择 2 = 6(其中 k 选择 2 = k(k- 1)/2)。”意思是。这个不清楚。以上是关于计算给定总和为零的所有连续子数组的主要内容,如果未能解决你的问题,请参考以下文章
给定一个数组,打印所有可能的连续子序列,其总和可被给定数 x 整除
谷歌面试:在给定的整数数组中找到所有连续的子序列,其总和在给定范围内。我们能比 O(n^2) 做得更好吗?