后缀数组可以用于此问题。它们包含按字典顺序排序的字符串的每个后缀的起始位置。即使可以以复杂度天真地构造它们,也有一些以复杂度构造它们的方法。例如参见this和this。让我们将此后缀数组称为SA。Θ (n )O(nlogn)Θ(n)
构造后缀数组后,我们需要为后缀数组构造一个最长公共前缀(LCP)数组。LCP数组存储后缀数组(按字典顺序的后缀)中两个连续前缀之间最长的公共前缀的长度。因此,LCP [i]包含SA [i]和SA [i + 1]之间最长的公共前缀的长度。该数组也可以线性时间构造:请参见此处,此处和此处以获取一些参考。
现在,要计算后缀树中任何两个后缀(而不是连续的后缀)所共有的最长前缀的长度,我们需要使用一些RMQ数据结构。上面的参考文献已经显示了这一点(如果将数组可视化为后缀树,则很容易看到),即后缀数组中位置为和()的两个后缀之间的最长公共前缀的长度可以作为。一个好的RMQ可以预先处理阵列中或时间和响应形式的查询在v u < v m i n u < = k < = v − 1 L C P [ k ] L C P O (n )O (n log n )L C P [ u ,v ] O (1 )uvu<vminu<=k<=v−1LCP[k]LCPO(n)O(nlogn)LCP[u,v]O(1)时间。见这里的succint RMQ算法,并在这里对RMQ的一个很好的教程,和LCA和RMQs之间的关系(及还原)。这是另一种不错的替代方法。
利用此信息,我们构造了后缀数组和相关数组(如上所述),用于两个字符串之间的分隔符(例如T#P,其中两个字符串中均不出现“#”)。然后,我们可以使用“袋鼠”方法执行k个不匹配字符串匹配。这和本说明中后缀树的上下文中,袋鼠方法,而是可以直接施加到后缀阵列太。对于每一个索引的文本的,发现的后缀的开始在和后缀从0开始。这给出了在此之后,第一个不匹配时发生匹配的位置T L C P T i P P T [ i ] l 0 T P L C P T [ i + l 0 + 1 ] P [ l 0 + 1 ] k L C P O (1 )O (k )L C P 我ŤiTLCPTiPP与。将该长度设为。跳过和不匹配的字符,然后尝试匹配其余的字符串。即,再次发现的和。重复此过程,直到获得不匹配项,或者任一字符串完成。每个为。有的每个索引的,这给人的总的复杂性。T[i]l0TPLCPT[i+l0+1]P[l0+1]kLCPO(1)O(k) LCPiTO(nk)
我使用了一种更容易实现的RMQ来实现总复杂度或如果,但是它如上所述,也可以在完成。可能还有其他直接方法可以解决此问题,但这是一种功能强大且通用的方法,可以应用于许多类似的问题。O(nk+(n+m)log(n+m))O(nk+nlogn)m=O(n)O(nk)