假设有一个E
元素的数组2^n
。例如:
E = [2, 3, 5, 7, 11, 13, 17, 19]
不幸的是,有人出现并乱扰阵列。他们采用二进制索引为1XX
形式的所有元素,并将它们添加到索引0XX
的元素中(即它们E[0] += E[1]
,E[2] += E[3]
等。然后对X1X
等X0X
和XX1
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?这更难吗?
答案 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
个自由度,我们不能使用其他元素重写任何一个元素的用法。希望这很清楚。加扰分配第一个项目的方式要求您查看每个项目以获取它。