对阵列的连续子阵列进行异或

时间:2017-01-11 09:13:25

标签: python arrays algorithm python-3.x bit-manipulation

从数组中,我需要找到通过对连续子阵列进行异或所获得的值,然后对如此获得的值进行异或。

INPUT

一行包含作为数组元素的整数。

e.g。 [1,2,3]

输出

在单独的行中打印与每个测试用例相对应的答案。

到目前为止,我设法使用循环和递归方法构建两个策略。 我的方法都没有在大输入大小上表现出色。

e.g。 1 XOR 2 XOR 3 XOR(1 XOR 2)XOR(2 XOR 3)XOR(1 XOR 2 XOR 3)= 2

你能建立一个更好的算法吗?也许是一种动态编程方法?

from functools import reduce

# Calculate the XOR
def XOR(L):
    return reduce(lambda x, y: x ^ y, L)

# Recursive approach
def allSubArraysXOR(L,L2=None):
    if L2==None:
        L2 = L[:-1]
    if L==[]:
        if L2==[]:
            return 0
        return allSubArraysXOR(L2,L2[:-1])
    return XOR(L) ^ allSubArraysXOR(L[1:],L2)

# Loop - yielding approach
def getAllWindows(L):
    for w in range(1, len(L)+1):
        for i in range(len(L)-w+1):
            yield XOR(L[i:i+w])

a = [int(a_temp) for a_temp in input().strip().split(' ')]
print(allSubArraysXOR(a))
# print(XOR(getAllWindows(a)))

1 个答案:

答案 0 :(得分:8)

我们不需要枚举(2 ** n)子阵列来解决此问题。

XOR有一些有用的属性,我们可以利用它来在O(n)时间内解决这个问题。具体做法是:

要解决您的问题,我们首先需要计算每个元素在子数组中出现的次数。出现偶数次的任何元素都可以忽略不计。其余的需要一起进行异或(每次只需一次)。

让我们看看这适用于您的示例:

1 XOR 2 XOR 3 XOR (1 XOR 2) XOR (2 XOR 3) XOR (1 XOR 2 XOR 3) = # open brackets
1 XOR 2 XOR 3 XOR 1 XOR 2 XOR 2 XOR 3 XOR 1 XOR 2 XOR 3 =       # reorder
1 XOR 1 XOR 1 XOR 2 XOR 2 XOR 2 XOR 2 XOR 3 XOR 3 XOR 3 =       # group
(1 XOR 1 XOR 1) XOR (2 XOR 2 XOR 2 XOR 2) XOR (3 XOR 3 XOR 3) = # remove pairs
1 XOR 0 XOR 3 =
1 XOR 3 =
2

以下是这个想法的O(n)实现:

def xor_em(lst):
  n = len(lst)
  ret = 0
  for i, el in enumerate(lst):
    count = (i + 1) * (n - i)
    if count % 2:
      ret ^= el
  return ret

print xor_em([1, 2, 3])

子阵列的计数由

完成
count = (i + 1) * (n - i)

使用观察结果显示当前元素(包括其自身)左侧有i + 1个元素,右侧有n - i元素(也包括其自身)。将两者相乘得出从当前元素左侧开始的子数组的数量,并在其右侧结束。

我们现在已将问题缩小为寻找产品为奇数的对(i + 1)(n - i)。观察到获得奇数乘积的唯一方法是将两个本身相乘的数相乘(这可以通过考虑两个被乘数的主要因子来看出)。

有两种情况需要考虑:

  • n为偶数时,(i + 1)(n - i)中的一个始终是偶数。这意味着对于偶数长度的列表,算法总是返回零。
  • n为奇数时,(i + 1) * (n - i)对于i = 0, 2, 4, ..., (n - 1)来说是奇数。

这导致以下简化的解决方案:

def xor_em(lst):
  if len(lst) % 2 == 0:
    return 0
  else:
    return reduce(operator.xor, lst[::2])