查找数组的Xor

时间:2017-03-20 11:59:57

标签: algorithm binary numbers bit-manipulation bitmask

我有一个长度为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不是关联的所以我们不能采取简单的方法吗?

2 个答案:

答案 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)。