我有一个长度为n
的数组A和长度为B
的数组m
。我必须找到以下值。
long ans=0;
for(int i:B)
{
xor=0;
for(int j:A) xor+=j^i;
ans+=xor
}
print ans
时间复杂度 O(N * M )。 总之,我必须找到这个值
(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 ......)......等等
如何以更好的时间复杂度找到这个值?我认为 XOR不是关联的所以我们不能采取简单的方法吗?
答案 0 :(得分:4)
考虑一个特定的位(比如说第10位)。假设数组的长度为100,并且在A
中设置了第19个第10位的元素,在B
中设置了第10个第10位的元素。集合(A[i]^B[j] for i=1..N, for j=1..M)
中有多少元素将设置第10位?好吧,它需要A[i]
中设置的位而不是B[j]
中的位,反之亦然。所以有19 *(100-22)+(100-19)* 22个元素,第10位设置。这个计算表明我们可以有效地逐位执行求和。
更确切地说,假设您有32位整数。对于0..31中的每个i,让我们用该位设置计算A和B的元素数。假设我们在A中有一个[i]元素,在B中有b [i]个元素,并且第i位被设置。
使用与上面相同的想法,这些第i位的xor之和将对整体结果贡献(a[i]*(len(B)-b[i]) + (len(A)-a[i])*b[i]) << i
。
这为您提供了一个简单的O((N + M)k)解决方案(其中k是数组中任何int中最大的位数)。
这是一些实现这个想法的Python代码,包括针对天真版本的一些随机测试:
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和B上迭代一次可能会更快,并且在两个数组中一次性累加32位计数,因为这样可以最大限度地减少内存读取。 (事实上,这是我的代码的第一个版本的工作方式)。但是我将代码更改为上面的代码,因为它更简单,并且具有相同的复杂性。
答案 1 :(得分:-1)
这是一个建议:
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;
如果我没有弄错的话,这个算法应该是O(N + M)。