这是谷歌最近的一个面试问题:
我们将 f(X, Y) 定义为 X 和 Y 的二进制表示中不同对应位的数量。例如,f(2, 7) = 2,因为 2 和 7 的二进制表示分别为 010 和 111。第一位和第三位不同,所以 f(2, 7) = 2。
给定一个由 N 个正整数组成的数组,A1, A2 ,..., AN。求所有对 (i, j) 的 f(Ai, Aj) 之和,使得 1 ≤ i, j ≤ N
例如:
A=[1, 3, 5]
我们返回
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
我可以想到这个解决方案是 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]);
}
}
我能想到的另一种方法是(考虑到每个元素只包含一个二进制数字):
- 从数组末尾开始
- 记录到目前为止发现的 1 和 0
- 如果当前元素为 1,那么它将对
count_of_zeros
最终总和有所贡献 - 像这样继续直到我们到达数组的开头。
这种方法是否正确。