-1

You are given an array of n integers a0, a1, .. an , and a positive integer k. Find and print the number of pairs (i,j) where and i+j is evenly divisible by k (Which is i+j % k == 0). This problem has been taken from here.

We need a solution in O(n) time.

An explanation is that we can do this by separating elements into buckets depending on their mod k. For example, you have the elements: 1 3 2 6 4 5 9 and k = 3

mod 3 == 0 : 3 6 9
mod 3 == 1 : 1 4
mod 3 == 2 : 2 5

Then, it is said:

Now, you can make pairs like so: Elements with mod 3 == 0 will match with elements with (3 - 0) mod k = 0, so other elements in the mod 3 == 0 list, like so: (3, 6) (3, 9) (6, 9)

Further:

There will be n * (n - 1) / 2 such pairs, where n is length of the list, because the list is the same and i != j. Elements with mod 3 == 1 will match with elements with (3 - 1) mod k = 2, so elements in the mod 3 == 2 list, like so: (1, 2) (1, 5) (4, 2) (4, 5)

It makes sense that (3, 6) (3, 9) (6, 9) ( all items in the 0th bucket be paired) since (a + b)% k = 0 = a % k + b % k.

What isnt clear is how the other pairs were generated by combination of elements in the 1st (mod 3 == 1) and the 2nd (mod 3 == 2) bucket and why would there be n * (n - 1) / 2 pairs. Is there another (better) method?

This question is suitable for Math Stackexchange, whose existance I was not aware of before posting the question.

FlyingAura
  • 1,541
  • 5
  • 26
  • 41

4 Answers4

2

I translate the C code...

using namespace std;
int main(){

   int n;
   int k;
   cin >> n >> k;
   int a[n];
   int m[k];
   for(int i=0; i<k; i++)
       m[i]=0;
    for(int i = 0; i < n; i++){
       cin >> a[i];
        m[a[i]%k]++;
    }
    int sum=0;
    sum+=(m[0]*(m[0]-1))/2;
     for(int i=1; i<=k/2 && i!=k-i; i++){
         sum+=m[i]*m[k-i];
     }
    if(k%2==0)
        sum+=(m[k/2]*(m[k/2]-1))/2;
    cout<<sum;
    return 0;
}

into Python:

def divisible_sum_pairs(n, k, a_list):
    m = [0] * len(a_list)
    for a in a_list:
        m[a % k] += 1

    sum = int(m[0] * (m[0] - 1) / 2)
    for i in range(1, int(k / 2) + 1):
        if i != k - 1:
            sum += m[i] * m[k - i]
    if k % 2 == 0:
        sum += m[int(k / 2)] * (m[int(k / 2)] - 1) / 2

    return sum

With:

print(divisible_sum_pairs(6, 3, [1,  3,  2,  6,  1,  2]))

You get 5

Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
1

You have n * (n - 1) / 2 pairs because everyone (n) can be paired with everyone else (n-1); but since the order doesn't matter we avoid counting mirror pairs by dividing by two.

Also remainders over the same quotient are summed when the numerators are summed, but the reminder cannot be more than the quotient. A reminder of 3 in a division by 3 is actually a reminder of 0.

The answer is very clever, you can probably make it a few percent faster with low-level optimizations; for instance implementing a dedicated module-by-3 rather than relying on the general algorithm of %; but you cannot really beat O(n) as you need to scan every element at least once, and the solution is already not doing much more. (in fact, as you are asked to write the result, it seems to me you cannot do it in less than O(n^2) just because of that...)

None of these questions has anything to do with python. Did you know there is a math.stackexchange.com?

Community
  • 1
  • 1
Francesco Dondi
  • 1,064
  • 9
  • 17
  • I did not know about Math stack exchange, This question should rightly be there. Thanks for that information – FlyingAura Jul 15 '16 at 18:00
0

This solution works for me for large values of K. For smaller values Laurent's solution is better.

def numPairsDivisibleByK(arr, k): freq = [0 for i in range(k)] for i in arr: freq[i % k] += 1

count = int(freq[0] * (freq[0] - 1) / 2)
for i in range(1, int(k / 2) + 1):
    if i == 0:
        count += int(freq[0] * (freq[0] - 1) / 2)
    elif float(i) == (k/2):
        count += int(freq[int(k/2)] * (freq[int(k/2)] - 1) / 2)
    else:
        count += int(freq[i] * freq[k-i])   

return count

print numPairsDivisibleByK([30,20,150,100,40], 60)

Aditya Avs
  • 41
  • 1
  • 5
0

def divisibleSumPairs(n, k, ar):

counter=0

for i in range(n):
    if i<n:
        for j in range(i+1,n):
            addn=ar[i]+ar[j]
            if addn%k ==0:
                counter=counter+1
                
return(counter)
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 02 '22 at 12:23