查找数组的异或
Find Xor of an Array
我有一个长度为 n
的数组 A 和一个长度为 m
的数组 B
。我必须找到以下值。
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 不是关联的 所以我们不能采取简单的方法吗?
这里有一个建议:
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)。
考虑一个特定的位(比如第 10 个)。假设数组的长度为 100,并且有 19 个元素的第 10 位设置为 A
,还有 22 个元素的第 10 位设置为 B
。集合 (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 中有 a[i] 个元素,在 B 中有 b[i] 个元素,第 i 个位被设置。
使用与上述相同的想法,这第 i 位的异或之和将为整体结果贡献 (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 位计数可能会更快,因为这样可以最大限度地减少内存读取。 (事实上,这就是我的代码的第一个版本的工作方式)。但是我把代码改成了上面的,因为这样简单很多,复杂度也一样。
我有一个长度为 n
的数组 A 和一个长度为 m
的数组 B
。我必须找到以下值。
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 不是关联的 所以我们不能采取简单的方法吗?
这里有一个建议:
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)。
考虑一个特定的位(比如第 10 个)。假设数组的长度为 100,并且有 19 个元素的第 10 位设置为 A
,还有 22 个元素的第 10 位设置为 B
。集合 (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 中有 a[i] 个元素,在 B 中有 b[i] 个元素,第 i 个位被设置。
使用与上述相同的想法,这第 i 位的异或之和将为整体结果贡献 (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 位计数可能会更快,因为这样可以最大限度地减少内存读取。 (事实上,这就是我的代码的第一个版本的工作方式)。但是我把代码改成了上面的,因为这样简单很多,复杂度也一样。