在匹配位掩码的索引处给定项的总和,恢复数组的元素

时间:2015-01-24 21:26:55

标签: algorithm

假设有一个E元素的数组2^n。例如:

E = [2, 3, 5, 7, 11, 13, 17, 19]

不幸的是,有人出现并乱扰阵列。他们采用二进制索引为1XX形式的所有元素,并将它们添加到索引0XX的元素中(即它们E[0] += E[1]E[2] += E[3]等。然后对X1XX0XXX1 XX0等索引做了同样的事情。

更具体地说,他们在数组上运行了这个伪代码:

def scramble(e):
    n = lg_2(len(e))
    for p in range(n):
        m = 1 << p
        for i in range(len(e)):
            if (i & m) != 0:
                e[i - m] += e[i]

就我们的例子而言,这会导致:

E_1 = [2+3, 3, 5+7, 7, 11+13, 13, 17+19, 19]
E_1 = [5, 3, 12, 7, 24, 13, 36, 19]

E_2 = [5+12, 3+7, 12, 7, 24+36, 13+19, 36, 19]
E_2 = [17, 10, 12, 7, 60, 32, 36, 19]

E_3 = [17+60, 10+32, 12+36, 7+19, 60, 32, 36, 19]
E_3 = [77, 42, 48, 26, 60, 32, 36, 19]

你被加扰后给你的数组(即你的输入是E_3)。您的目标是恢复E的原始第一个元素(即数字2)。

获得2回的一种方法是撤消所有加扰。运行加扰代码,但+=替换为-=。但是,这样做非常昂贵。这需要n 2^n时间。有更快的方法吗?

替代表格

换句话说,我给你一个数组S,其中索引i的元素是列表中j满足(j & i) == i的所有元素的总和E。例如,S[101110]E[101110] + E[111110] + E[101111] + E[111111])。在给定E的情况下恢复S的元素有多贵?

111111...上的项目很简单,因为S[111111...] = E[111111...],但S[000000...]取决于所有E中的元素统一的方式所以似乎更难回来。

扩展

如果我们不仅想要恢复原始项目,而是希望恢复与可以指定必须为1,无约束,必须是0?这更难吗?

1 个答案:

答案 0 :(得分:0)

调用数组N中的项目数,以及正在使用的位掩码的大小B,以便N = 2^B

你不能比O(N)做得更好。

问题中的示例解决方案,只是反向运行加扰,需要O(N B)时间。我们可以通过丢弃不会影响我们最后读取的实际值的项目来将其减少到O(N)。这使得解密变得更加简单,实际上:只是从上半部分迭代地减去数组的后半部分,然后丢弃后半部分,直到剩下一个项目为止。

def unscrambleFirst(S):
    while len(S) > 1:
        h = len(S)/2
        for i in range(h):
            S = S[:h] - S[h:] #item-by-item subtraction
    return S[0]

不可能比O(N)更快。我们可以用线性代数证明它。

  • 原始数组包含N个独立项目,即它是一个N自由度的向量。
  • 加扰操作仅使用线性运算,因此相当于将该向量乘以矩阵。 (矩阵为[[1, 1], [0, 1]] tiled inside of itself B次;最终看起来像Sierpinski triangle)。
  • 加扰操作矩阵是可逆的(这就是我们可以撤消加扰的原因)。
  • 因此,加扰矢量必须具有N自由度。
  • 但我们的O(N)解决方案是加扰矢量的每个元素的线性组合。
  • 由于加扰向量的元素必须全部线性独立,因为其中有N个自由度,我们不能使用其他元素重写任何一个元素的用法。
  • 因此,我们无法改变我们所依赖的项目,并且我们知道在一个案例中我们依赖所有这些项目,因此在所有情况下都必须全部。

希望这很清楚。加扰分配第一个项目的方式要求您查看每个项目以获取它。