我有两个文件 - 让我们称它们为file0和file1。
我想得到的是针对以下问题的快速算法(我很清楚如何编写一个解决它的相当慢的算法):
检测作为file1前缀的file0的最大后缀,表示最大长度的内存块B(或更确切地说:此类内存块的字节数),以便
请注意,块A,B和C的长度也可以是零字节。
编辑(回答drysdam的评论):我想到的明显相当慢的算法(伪代码):让文件的长度以m,n为界,wlog m <= n。
for each length from m to 0
compare the m last bytes of file0 with the first m bytes of file1
if they are equal
return length
这显然是O(m * min(m,n))算法。如果文件大小相同,则为O(n ^ 2)。
我目前要处理的文件大小为10到几千兆字节。但在极端情况下,它们的大小也可能只有几千兆字节 - 只要大到不能再适应x86的32位地址空间了。
答案 0 :(得分:3)
考虑将你的字节视为数字0..255,保持为整数mod p,其中p是素数,可选地远大于255.这里有两种计算方法b0 * x ^ 2 + b1 * x + b2:< / p>
(b0 * x + b1)* x + b2
b0 * x ^ 2 +(b1 * x + b2)。
因此,我可以通过从左到右的工作来有效地计算这个数量 - 乘以x并添加b2,或者从右到左工作 - 添加b0 * x ^ 2.
选择一个随机x并计算它在AB中从右到左工作,在BC中从左到右计算。如果计算的值匹配,则记下该位置。稍后对从最长的比赛开始的所有比赛进行慢速检查,以确定在两种情况下B是否真的相同。
随机比赛的几率是多少?如果你有一个错误的匹配则(a0-c0)* x ^ 2 +(a1-c1)* x +(a2-c2)= 0.一个d次多项式最多有d个根,所以如果x是随机的,错误匹配的可能性最多是d / p,你可以通过为适当大的p工作mod p来做到这一点。 (如果我没记错的话,有一个消息认证方案,其核心是这个想法)。
答案 1 :(得分:1)
根据您可用的内存量,您可能需要考虑为第一个文件构建后缀树。一旦你有了这个,你可以通过沿着与第二个文件的前缀字母匹配的边缘从根向下走后缀树来查询与第二个文件的后缀最大重叠的第二个文件的前缀。由于后缀树可以在线性时间内构建,因此该算法的运行时使用您的术语为O(| A | + | B |),因为它需要O(| A | + | B |)时间来构建后缀树和O(| B |)时间走后缀树以找到块B.
答案 2 :(得分:1)
如果它不是一项学术任务,那么实施最简单的解决方案并了解它对您的数据的行为可能是有意义的。
例如,理论上更高效的基于Knuth-Morris-Pratt算法的解决方案可能比基于IndexOf的解决方案表现更差(参见Overlap Detection)。
对于大型文件,您的程序可能会花费所有时间等待I / O.