How to find all ordered pairs of elements in array of integers whose sum lies in a given range of value

前端 未结 8 1031
抹茶落季
抹茶落季 2021-02-05 21:58

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 <

8条回答
  •  野趣味
    野趣味 (楼主)
    2021-02-05 22:21

    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()
    

    A word of caution:

    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....

提交回复
热议问题