我正在尝试找到一种搜索多位数组最长前缀的快速算法。在我的应用程序中,那些位数组可以是无限长且可变长度的。例如,如果我有这些位数组:
0b1011001
0b1001101
0b1001010
0b1010100
最长的前缀是10.我正在对位数进行ORing和NAND运算以找到它们的公共0和1并将结果进行异或。
OR
0b1011111
NAND
0b0111111
XOR
0b1100000
有更快的解决方案吗?
它在位数的数量上很好地(线性)扩展。
它在比特阵列的大小上不能很好地扩展,理想情况下它应该根据公共前缀的长度而不是比特阵列的大小来扩展。
来自位数组的单个字节/字的位操作应该比一次一个地沿位移动快得多。 (不知道Python可以给你多少低级控件)。
如果这是像C这样的低级语言,我会以类似于你的方式解决这个问题,但是从其他答案中得到一些想法。
在我的例子中,我将假设计算机是64位计算机。
我从(OR NAND XOR)开始,只是每个位阵列的前64位(这些是64位机器上的基本操作,复杂性只是O(阵列数))。
然后快速找到结果中第一个设置位的位置(大多数计算机都有一些内置的快速方法或至少在优化的汇编代码中,for C,如果有一个设置位,则返回该值。
否则,重复每个位阵列的下一个64-127位。
(您可能需要以某种方式处理不同长度的位数组,可能通过查找该组的最小长度位数组,然后将其用作最大值)。
这种方法的好处是它的位数是线性的,并且线性是公共前缀的长度。
如果存在大量位阵列,则可以通过使用并行性来获得加速。
首先,您可以在NAND的同时运行OR。
有了更多的聪明才智,您可以应用以下内容:
如果我有4位数组A,B,C,D
而不是(((A OR B)或C)或D)
我可以做(A或B)或(C或D)。
在这两种情况下,都进行了相同数量的OR。
但是第二种方法可以有效地并行化(实际上,第二种方法可以在单核机器上更快地进行,因为CPU实际上通常会有多个ALU。)
写出逻辑有点棘手,因为你不能使用单个for循环和一个保存OR结果的临时变量。
您可以想象将子结果存储在长度为位数数量一半的数组中。将A OR B的子结果存储在数组[0]和数组[1]中的C OR D中,然后执行数组[0] OR数组[1]。 (并且您可以将结果存储在长度减半的新数组中,或者覆盖数组中的值以节省空间和内存分配)。
将工作分成足够大的块以保持整个计算机的繁忙而不会引入太多开销。
有了足够的处理器,您可以接近位数的对数而不是线性的日志的复杂性。但实际上,在6核机器上获得5倍的加速可能会相当不错。
您不需要对所有阵列进行ORing或NANDing(这将非常昂贵,因为它们是任意长的)。当您发现第一个不匹配时,您可以从左到右扫描阵列。这将是O(kn),其中n是数组的数量,k是公共前缀的长度。
我的python非常糟糕,所以我只给出一个非常简单的例子,它有2个固定等长的数组,只是为了清楚:
a = [1,0,1,1,0,0,1]
b = [1,0,1,1,0,1,1]
for x in xrange(0,7):
if a[x] != b[x]:
print a[0:x]
break
output:
[1, 0, 1, 1, 0]
显然你必须解决这个问题,如果你理解代码背后的逻辑,我想我会很容易。
在某些情况下,最佳解决方案是使用prefix trees它具有O(n)的复杂度,其中n是二进制字符串的共享前缀的总和但具有大系数。
假设你有输入字符串s1,s2,s3 ......
在最坏的情况下,s1和s2可以是相同的,在这种情况下你可以使用启发式(例如,首先将s的初始长度限制为k = 100。如果最终的s仍然是长度k = 100,则重复整个过程,但是从每个字符串的位置k + 1开始)。