我正在尝试找到一种搜索多位数组最长前缀的快速算法。在我的应用程序中,那些位数组可以是无限长且可变长度的。例如,如果我有这些位数组:
0b1011001
0b1001101
0b1001010
0b1010100
最长的前缀是10。 我正在对位阵列进行ORing和NAND处理以找到它们的公共0和1并将结果进行异或。
OR
0b1011111
NAND
0b0111111
XOR
0b1100000
有没有更快的解决方案?
答案 0 :(得分:2)
它在位数的数量上很好地(线性)。
它在位数的大小上不能很好地扩展,理想情况下它应该根据公共前缀的长度而不是位数组的大小进行扩展。
来自位数组的单个字节/字的位操作应该比一次一个地沿着位移动快得多。 (不知道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倍的加速可能会非常好。
答案 1 :(得分:1)
您不需要对所有阵列进行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]
显然你必须解决这个问题,如果你不知道代码背后的逻辑,我想我会很容易。
答案 2 :(得分:0)
在某些情况下,最佳解决方案是使用prefix trees它具有O(n)的复杂度,其中n是二进制字符串的共享前缀的总和,但系数较大。
答案 3 :(得分:0)
假设你有输入字符串s1,s2,s3 ......
在最坏的情况下,s1和s2可以是相同的,在这种情况下你可以使用启发式(例如,首先将s的初始长度限制为k = 100。如果最终的s仍然是长度k = 100,则重复整个过程,但从每个字符串的位置k + 1开始。)