We'll see; your array looks something like this:
int[] data = new int[] { 6, -2, 3, 2, 0, 0, 5, 7, 0, -2 };
you can add to zero in two different ways:
- a + (-a) // positive + negative
- 0 + 0 // any two zeros
in the example above there are five pairs:
-2 + 2 (two pairs): [1] + [3] and [3] + [9] 0 + 0 (three pairs): [4] + [5], [4] + [8] and [5] + [8]
So you have to keep track of positive / negative pairs and zeros. Implementation
Dictionary<int, int> positives = new Dictionary<int, int>(); Dictionary<int, int> negatives = new Dictionary<int, int>(); int zeros = 0; foreach(var item in data) { int v; if (item < 0) if (negatives.TryGetValue(item, out v)) negatives[item] = negatives[item] + 1; else negatives[item] = 1; else if (item > 0) if (positives.TryGetValue(item, out v)) positives[item] = positives[item] + 1; else positives[item] = 1; else zeros += 1; }
Note that sorts and dictionaries (for example, hash tables) are not used for positive and negative values, so the runtime will be linear, O(n) ; the dark side of the implementation is that it requires two additional structures (i.e. additional memory). In your case (only millions of integers are megabytes) you have this memory.
Edit: terser but less readable Linq solution:
var dict = data .GroupBy(item => item) .ToDictionary(chunk => chunk.Key, chunk => chunk.Count()); int result = dict.ContainsKey(0) ? dict[0] * (dict[0] - 1) / 2 : 0; result += dict .Sum(pair => pair.Key > 0 && dict.ContainsKey(-pair.Key) ? pair.Value * dict[-pair.Key] : 0);
Dmitry Bychenko
source share