根据关于Rabin-Karp字符串匹配算法的wikipedia entry,它可以用于同时在字符串中查找几种不同的模式,同时仍保持线性复杂性。很明显,当所有模式具有相同的长度时,这很容易完成,但是当我同时搜索具有不同长度的模式时,我仍然不知道如何保持O(n)复杂度。有人可以对此有所了解吗?
编辑(2011年12月):
维基百科文章已经更新,不再声称匹配O(n)中不同长度的多种模式。
答案 0 :(得分:5)
我不确定这是否是正确答案,但无论如何:
在构造哈希值时,我们可以检查字符串哈希值中的匹配项。 Aka,当前哈希值。散列函数/代码通常实现为循环,在循环内部我们可以插入快速查找。
当然,我们必须选择m
以获得字符串集中的最大字符串长度。
更新:来自维基百科,
[...]
for i from 1 to n-m+1
if hs ∈ hsubs
if s[i..i+m-1] = a substring with hash hs
return i
hs := hash(s[i+1..i+m]) // <---- calculating current hash
[...]
我们在m
步骤中计算当前哈希值。在每一步中都有一个临时哈希值,我们可以在哈希集中查找(O(1)复杂度)。所有散列都具有相同的大小,即32位。
更新2:摊销(平均)O(n)时间复杂度?
上面我说m
必须有最大字符串长度。事实证明,我们可以利用相反的情况
使用hashing for shifting substring search和固定m
大小,我们可以实现O(n)复杂度。
如果我们有可变长度字符串,我们可以将m
设置为最小字符串长度。另外,在散列集合中,我们不会将散列与整个字符串相关联,而是将其与第一个m字符相关联
现在,在搜索文本时,我们检查当前哈希是否在哈希集中,并检查匹配的关联字符串。
这种技术会增加误报,但平均而言,它具有O(n)时间复杂度。
答案 1 :(得分:0)
这是因为子串的哈希值在数学上是相关的。计算散列 H(S,j)(从字符串 S 的第j个位置开始的字符的散列)需要 O(m)时间长度为 m 的字符串。但是一旦你有了,计算 H(S,j + 1)就可以在恒定时间内完成,因为 H(S,j + 1)可以表示为 H(S,j)的功能。
O(m)+ O(1)=&gt; O(m),即线性时间。
Here's a link这里有更详细的描述(参见例如“什么使Rabin-Karp禁食?”)