你已经给出了一个数组,你必须给出连续子数的数量,其总和为零。
example:
1) 0 ,1,-1,0 => 6 {{0},{1,-1},{0,1,-1},{1,-1,0},{0}};
2) 5, 2, -2, 5 ,-5, 9 => 3.
使用O(n ^ 2)可以完成。我正在尝试找到低于这种复杂性的解决方案。
答案 0 :(得分:7)
考虑数组的S [0..N] - prefix sums,即S [k] = A [0] + A [1] + ... + A [k-1] 0到N。
当且仅当S [R] = S [L]时,从L到R-1的元素之和为零。这意味着你必须找到索引的数量0< = L< R< = N,使得S [L] = S [R]。
这个问题可以通过哈希表来解决。迭代S []的元素,同时为S []的已处理部分中的每个值维持X次。这些计数应存储在哈希映射中,其中数字X是键,计数H [X]是值。当你遇到一个新元素S [i]时,在你的答案中添加H [S [i]](这些用于以(i-1)-st元素结尾的子串),然后将H [S [i]]加1
请注意,如果数组元素的绝对值之和很小,则可以使用简单数组而不是哈希表。复杂性平均线性。
以下是代码:
0
答案 1 :(得分:1)
这可以通过保持在数组遍历期间达到的总和的哈希表来在线性时间内解决。然后可以从重新计算的总和的数量直接计算子集的数量。
Haskell版本:
import qualified Data.Map as M
import Data.List (foldl')
f = foldl' (\b a -> b + div (a * (a + 1)) 2) 0 . M.elems . snd
. foldl' (\(s,m) x -> let s' = s + x in case M.lookup s' m of
Nothing -> (s',M.insert s' 0 m)
otherwise -> (s',M.adjust (+1) s' m)) (0,M.fromList[(0,0)])
输出:
*Main> f [0,1,-1,0]
6
*Main> f [5,2,-2,5,-5,9]
3
*Main> f [0,0,0,0]
10
*Main> f [0,1,0,0]
4
*Main> f [0,1,0,0,2,3,-3]
5
*Main> f [0,1,-1,0,0,2,3,-3]
11
答案 2 :(得分:0)
我不知道我的建议会有多复杂但我有一个想法:)
您可以做的是尝试从主数组中减少无法为您提供解决方案的元素
假设元素是#include <iostream>
using namespace std;
int main() {
long double pi;
pi = 3.14159265358979323846264338327950288419716939937510;
cout << "PI = " << pi << endl;
return 0;
}
所以你可以看到-10, 5, 2, -2, 5,7 ,-5, 9,11,19
是元素
永远不会对您的案件中-10,9,11 and 19
有用
所以尝试从主阵列中删除sum 0
要做到这一点,你可以做的是
-10,9,11, and 19
所以最后你得到一个包含-2,-5,5,7,2的数组,创建所有可能的子数组并检查sum = 0
(注意,如果输入数组包含0,则在最终数组中添加全0)
答案 3 :(得分:0)
我觉得可以使用DP解决: 让国家: DP [i] [j]表示使用以i结尾的所有子数组形成j的方式的数量!
<强>过渡:强>
对于初始步骤中的每个元素,
使用i元素增加形成Element[i]
的方法的数量,即使用从i开始并以i结尾的长度为1的子数组,即
DP[i][Element[i]]++;
然后为范围中的每个j [-Mod(任何元素的最高幅度),Mod(任何元素的最高幅度)]
DP[i][j]+=DP[i-1][j-Element[i]];
然后你的答案将是所有DP [i] [0]的总和(使用以i结尾的子数组形成0的方式的数量),其中i从1到元素数量变化
复杂性是O(任何元素的MOD最大量*元素数量)
答案 4 :(得分:0)
@stgatilov答案的https://stackoverflow.com/a/31489960/3087417的C#版本具有可读变量:
int[] sums = new int[arr.Count() + 1];
for (int i = 0; i < arr.Count(); i++)
sums[i + 1] = sums[i] + arr[i];
int numberOfFragments = 0;
Dictionary<int, int> sumToNumberOfRepetitions = new Dictionary<int, int>();
foreach (int item in sums)
{
if (sumToNumberOfRepetitions.ContainsKey(item))
numberOfFragments += sumToNumberOfRepetitions[item];
else
sumToNumberOfRepetitions.Add(item, 0);
sumToNumberOfRepetitions[item]++;
}
return numberOfFragments;
如果您不仅要使总和为零,而且要有任意个数k,这是提示:
int numToFind = currentSum - k;
if (sumToNumberOfRepetitions.ContainsKey(numToFind))
numberOfFragments += sumToNumberOfRepetitions[numToFind];
答案 5 :(得分:0)
https://www.techiedelight.com/find-sub-array-with-0-sum/
这将是一个精确的解决方案。
# Utility function to insert <key, value> into the dict
def insert(dict, key, value):
# if the key is seen for the first time, initialize the list
dict.setdefault(key, []).append(value)
# Function to print all sub-lists with 0 sum present
# in the given list
def printallSublists(A):
# create an empty -dict to store ending index of all
# sub-lists having same sum
dict = {}
# insert (0, -1) pair into the dict to handle the case when
# sub-list with 0 sum starts from index 0
insert(dict, 0, -1)
result = 0
sum = 0
# traverse the given list
for i in range(len(A)):
# sum of elements so far
sum += A[i]
# if sum is seen before, there exists at-least one
# sub-list with 0 sum
if sum in dict:
list = dict.get(sum)
result += len(list)
# find all sub-lists with same sum
for value in list:
print("Sublist is", (value + 1, i))
# insert (sum so far, current index) pair into the -dict
insert(dict, sum, i)
print("length :", result)
if __name__ == '__main__':
A = [0, 1, 2, -3, 0, 2, -2]
printallSublists(A)