Narendra Modi
Narendra Modi

Reputation: 861

Find Xor of an Array

I have an array A of length n and array B of length m. I have to find following below value.

 long ans=0;
 for(int i:B)
    {
           xor=0;
           for(int j:A) xor+=j^i;
           ans+=xor
    }
print ans

Time Complexity is O(N*M). In short I have to find this value

(A1^B1+A2^B1+A3^B1+A4^B1+A5^B1.....) + (A1^B2+A2^B2+A3^B2+A4^B2+A5^B2.....)+ (A1^B3+A2^B3+A3^B3+A4^B3+A5^B3.....)...... so on
How to find this value with better time complexity ? I think XOR is not associative so we can't take the easy way ?

Upvotes: 2

Views: 4343

Answers (2)

Paul Hankin
Paul Hankin

Reputation: 58409

Consider a particular bit (say the 10th). Suppose the arrays are of length 100, and there's 19 elements with the 10th bit set in A, and 22 elements with the 10th bit set in B. How many elements of the set (A[i]^B[j] for i=1..N, for j=1..M) will have the 10th bit set? Well, it needs either the bit set in A[i] and not in B[j] or vice versa. So there's 19*(100-22) + (100-19)*22 elements with the 10th bit set. This calculation suggests we can perform the sum bit-by-bit efficiently.

More precisely, suppose you have 32-bit ints. For each i in 0..31, let's count the number of elements of A and B with that bit set. Let's say we have a[i] elements in A, and b[i] elements in B with the i'th bit set.

Using the same idea as above, the sum of the xor of these i'th bits will contribute (a[i]*(len(B)-b[i]) + (len(A)-a[i])*b[i]) << i to the overall result.

This gives you a straightforward O((N+M)k) solution (where k is the largest number of bits in any int in your array).

Here's some Python code that implements this idea, including some randomised tests against the naive version:

def sum_xor(A, B):
    s = 0
    for i in xrange(32):
        ai = sum((a >> i) & 1 for a in A)
        bi = sum((b >> i) & 1 for b in B)
        s += (ai*(len(B)-bi) + (len(A)-ai)*bi) << i
    return s

def sum_xor_slow(A, B):
    s = 0
    for a in A:
        for b in B:
            s += a^b
    return s

import random

all_ok = True
for trials in xrange(100):
    A = [random.randrange(1<<32) for _ in xrange(random.randrange(100, 110))]
    B = [random.randrange(1<<32) for _ in xrange(random.randrange(100, 110))]
    x0 = sum_xor(A, B)
    x1 = sum_xor_slow(A, B)
    ok = x0 == x1
    all_ok = all_ok and ok
    print 'OK' if ok else 'FAIL', x0, x1
assert all_ok

A pragmatic note: it will probably be faster to iterate once over A and B, and accumulate the 32 bit counts all at once in two arrays, because that minimizes memory reads. (And indeed, this is how the first version of my code worked). But I changed the code to the above because it's a lot simpler and has the same complexity.

Upvotes: 4

Fernando Cezar
Fernando Cezar

Reputation: 848

Here's a suggestion:

let zeroes = number of zeroes in A;
let ones = number of ones in A;
let sum = 0;

for every i in B:
    if i == 0:
        sum += ones
    else:
        sum += zeroes
print sum;

This algorithm should be O(N+M), if I'm not mistaken.

Upvotes: -1

Related Questions