12

This is a recent interview question from Google:

We define f(X, Y) as number of different corresponding bits in binary representation of X and Y. For example, f(2, 7) = 2, since binary representation of 2 and 7 are 010 and 111, respectively. The first and the third bit differ, so f(2, 7) = 2.

You are given an array of N positive integers, A1, A2 ,…, AN. Find sum of f(Ai, Aj) for all pairs (i, j) such that 1 ≤ i, j ≤ N

For example:

A=[1, 3, 5]

We return

f(1, 1) + f(1, 3) + f(1, 5) + f(3, 1) + f(3, 3) + f(3, 5) + f(5, 1) + f(5, 3) + f(5, 5) =

0 + 1 + 1 + 1 + 0 + 2 + 1 + 2 + 0 = 8

I could think of this solution which is O(n^2)

int numSetBits(unsigned int A) {
    int count  = 0;

    while(A != 0) {
        A = A & (A-1);
        count++;
    }

    return count;
}

int count_diff_bits(int a, int b)
{
    int x = a ^ b;

    return numSetBits(x);
}

for (i = 0; i < n; i++)
   for (j = 0; j < n; j++) {
       sum += count_diff_bits(A[i], A[j]);
   }
}

Another approach i can think of is (considering that each element contains only one binary digit):

  • Start from the end of the array
  • keep a count of 1's and 0's found so far
  • If the current element is 1, then it will contribute count_of_zeros to the final sum
  • Continue like this till we reach the start of the array.

Is this approach correct.

Amit
  • 45,440
  • 9
  • 78
  • 110
pankaj
  • 1,316
  • 3
  • 16
  • 27
  • What makes you think "each element contains only one binary digit"? – Scott Hunter Oct 07 '15 at 15:45
  • @Scott, sorry i wasn't clear. It was just to simply the problem. If it works, we can enhance the approach for the complete set of bits. Just some random thought. – pankaj Oct 07 '15 at 15:52
  • You can easily reduce this to `O(n log n)` because `f(x,y) = f(y,x)` – Code Different Oct 07 '15 at 16:03
  • 2
    @Zoff, shouldn't that be O(n^2 / 2) , or I am missing something here. – pankaj Oct 07 '15 at 16:06
  • if we see the pattern in bits: 001 010 011 100 101 110 111 1000 The least significant bit changes on every iteration the bit after that changes every 2nd number the 3rd bit changes after every 4th number and so on and so forth Will post the solution after office hours – Shyamal Desai Oct 07 '15 at 16:55

2 Answers2

16

Iterate the array, and count number of "on" bits in each bit index, for example [1, 3, 5]:

0 0 1
0 1 1
1 0 1
-----
1 1 3

Now, for each bit counter, calculate:

[bit count] * [array size - bit count] * 2

and sum for all bits...

With example above:

3 * (3 - 3) * 2 = 0
1 * (3 - 1) * 2 = 4
1 * (3 - 1) * 2 = 4
          total = 8

To show why this works, lets look at a subset of the problem, using a single bit. Let's see what happens if we have an array with: [1, 1, 0, 0, 1, 0, 1]. Our count is 4 and size is 7. If we examine the first bit with all the bits in the array (including self, as in the question), we get:

1 xor 1 = 0
1 xor 1 = 0
1 xor 0 = 1
1 xor 0 = 1
1 xor 1 = 0
1 xor 0 = 1
1 xor 1 = 0

As can be seen, the contribution of this bit is the number of "off" bits. The same holds true for any other "on" bit. We could say that each "on" bit counts as the number of "off" bits:

[bit count] * [array size - bit count]

And where does the multiplication by 2 comes from? well, since we do the same with the "off" bits, except that for these, the contribution is the number of "on" bits:

[array size - bit count] * [bit count]

which of course is the same as above, and we can just multiply...

Complexity is O(n*k) where k is number of bits (32 in your code).

Amit
  • 45,440
  • 9
  • 78
  • 110
  • If the three numbers were 7, 7 and 7, shouldn't the answer be 18? It looks like your algorithm would report 0. – Scott Hunter Oct 07 '15 at 15:55
  • 1
    Unless I didn't understand `f(X, Y)`, then `f(7, 7) = 0`. – Amit Oct 07 '15 at 15:56
  • @Amit, nice !! The complexity in your case - shouldn't it be O(n*k) ? – pankaj Oct 07 '15 at 16:00
  • Also, is there any mathematical explanation for the expression you provided, or is it through observation / induction . – pankaj Oct 07 '15 at 16:01
  • 3
    For each bit-place, you compute (how many have a 1)*(how many have a 0), which gives you the number of ways to pair up values that differ on that bit. Then you double it, because (a,b) and (b,a) are considered distinct. Finally add up the values you computed for each bit-place. – Scott Hunter Oct 07 '15 at 16:21
0
#include <bits/stdc++.h>
#define MOD 1000000007ll
using namespace std;
typedef long long LL;

int solve(int arr[], int n) {

    int ans = 0;
    // traverse over all bits
    for(int i = 0; i < 31; i++) {

        // count number of elements with ith bit = 0
        long long count = 0;
        for(int j = 0; j < n; j++) if ( ( arr[j] & ( 1 << i ) ) ) count++;

        // add to answer count * (n - count) * 2
        ans += (count * ((LL)n - count) * 2ll) % MOD;
        if(ans >= MOD) ans -= MOD;
    }

    return ans;
}

int main() {

    int arr[] = {1, 3, 5};
    int n = sizeof arr / sizeof arr[0];
    cout << solve(arr, n) << endl; 
    return 0;
}
coderbhai
  • 41
  • 9