Given an array of integers find the number of all ordered pairs of elements in the array whose sum lies in a given range [a,b]
Here is an O(n^2) solution for the same <
I believe this is a simple math problem, that could be solved with numpy
with no loops and no sorting on our part. I'm not exactly sure, but I believe the complexity to be O(N^2) at worse case (would love some confirmation on that by someone more knowledgeable with time complexities in numpy).
At any rate, here's my solution:
import numpy as np
def count_pairs(input_array, min, max):
A = np.array(input_array)
A_ones = np.ones((len(A),len(A)))
A_matrix = A*A_ones
result = np.transpose(A_matrix) + A_matrix
result = np.triu(result,0)
np.fill_diagonal(result,0)
count = ((result > min) & (result < max)).sum()
return count
Now let's walk through it - first I just create a matrix with columns representing our numbers:
A = np.array(input_array)
A_ones = np.ones((len(A),len(A)))
A_matrix = A*A_ones
Let's assume that our input array looked like: [1,1,2,2,3,-1]
,thus, this should be the value of A_matrix
at this point.
[[ 1. 1. 2. 2. 3. -1.]
[ 1. 1. 2. 2. 3. -1.]
[ 1. 1. 2. 2. 3. -1.]
[ 1. 1. 2. 2. 3. -1.]
[ 1. 1. 2. 2. 3. -1.]
[ 1. 1. 2. 2. 3. -1.]]
If I add that to the transpose of itself...
result = np.transpose(A_matrix) + A_matrix
...I should get a matrix representing all combinations of sums of pairs:
[[ 2. 2. 3. 3. 4. 0.]
[ 2. 2. 3. 3. 4. 0.]
[ 3. 3. 4. 4. 5. 1.]
[ 3. 3. 4. 4. 5. 1.]
[ 4. 4. 5. 5. 6. 2.]
[ 0. 0. 1. 1. 2. -2.]]
Of course, this matrix is mirrored across the diagonal because the pairs (1,2) and (2,1) produce the same result. We don't want to consider these duplicate entries. We also don't want to consider the sum of an item with itself, so let's sanitize our array:
result = np.triu(result,0)
np.fill_diagonal(result,0)
Our result now looks like:
[[ 0. 2. 3. 3. 4. 0.]
[ 0. 0. 3. 3. 4. 0.]
[ 0. 0. 0. 4. 5. 1.]
[ 0. 0. 0. 0. 5. 1.]
[ 0. 0. 0. 0. 0. 2.]
[ 0. 0. 0. 0. 0. 0.]]
All that remains is to count the items that pass our criteria.
count = ((result > min) & (result < max)).sum()
This method won't work if 0
is in the acceptable domain, but I'm sure it would be trivial to manipulate that result matrix above to convert those 0's to some other meaningless number....