Algorithm 恢复数组的元素,给定索引处与位掩码匹配的项的总和
假设有一个由Algorithm 恢复数组的元素,给定索引处与位掩码匹配的项的总和,algorithm,Algorithm,假设有一个由2^n元素组成的数组E。例如: E = [2, 3, 5, 7, 11, 13, 17, 19] 不幸的是,有人来扰乱了阵列。他们获取了所有二进制索引形式为1XX的元素,并将它们添加到索引0XX的元素中(即,他们将e[0]+=e[1],e[2]+=e[3]等添加到0XX,并将XX1添加到XX0 更具体地说,他们在数组上运行了以下伪代码: def scramble(e): n = lg_2(len(e)) for p in range(n): m =
2^n
元素组成的数组E
。例如:
E = [2, 3, 5, 7, 11, 13, 17, 19]
不幸的是,有人来扰乱了阵列。他们获取了所有二进制索引形式为1XX
的元素,并将它们添加到索引0XX
的元素中(即,他们将e[0]+=e[1]
,e[2]+=e[3]
等添加到0XX
,并将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_3
),您将获得该数组。您的目标是恢复e
的原始第一个元素(即数字2)
恢复2的一种方法是撤消所有的加扰。运行加扰码,但是用-=
替换+=/code>。但是,这样做非常昂贵。需要n2^n
时间。有没有更快的方法
替代形式
换句话说,我给你一个数组S
,其中索引I
处的元素是所有元素的总和,索引j
满足列表(j&I)==I
。例如,S[101110]
是E[101110]+E[11111 0]+E[101111]+E[111111]
)。给定S
,恢复E
元素的成本有多高
111111…
中的项目很简单,因为S[111111…]=E[111111…]
,但是S[000000…]
以非统一的方式依赖于E
中的所有元素,因此似乎很难取回
扩展
如果我们不只是想恢复原始项,而是想恢复与掩码匹配的原始项的总和,该掩码可以指定must-be-1、无约束、和must-be-0,该怎么办?这更难吗?调用数组中的项数N
,以及正在使用的位掩码的大小B
soN=2^B
没有比O(N)
更好的了
问题中的示例解决方案只是反向运行置乱,需要O(nb)
时间。我们可以通过丢弃那些不会影响我们在最后读取的实际值的项目,将其减少到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]]
B
次;它最终看起来像a)
- 置乱操作矩阵是可逆的(这就是为什么我们可以撤消置乱)
- 因此,加扰向量必须仍然具有
N
自由度
- 但是我们的
O(N)
解是加扰向量的每个元素的线性组合
- 由于加扰向量的元素都必须是线性独立的,才能有
N
自由度,我们不能用其他元素的用法重写任何一个元素的用法
- 因此,我们不能改变我们所依赖的项目,我们知道我们在一种情况下依赖所有项目,所以在所有情况下都必须依赖所有项目
希望这足够清楚。混乱分配第一个项目的方式要求您查看每个项目才能将其取回。我很难理解您所说的内容。首先,您是指n=3
,因此E
具有2^3=8
元素吗?“他们拿走了所有二进制索引的元素…”让我困惑。你能给出这个加扰程序的(伪)代码吗?你能介绍一下你的n2^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]