使用通配符生成 Knuth–Morris–Pratt 前缀表
Posted
技术标签:
【中文标题】使用通配符生成 Knuth–Morris–Pratt 前缀表【英文标题】:Knuth–Morris–Pratt prefix table generation with wildcard 【发布时间】:2016-02-22 22:40:30 【问题描述】:我正在实现一个支持通配符的 KMP 字节模式搜索。下面是生成前缀表WITHOUT通配符的算法:
vector<int> PrefixFunction(string S)
vector<int> p(S.size());
int j = 0;
for (int i = 1; i < (int)S.size(); i++)
while (j > 0 && S[j] != S[i])
j = p[j-1];
if (S[j] == S[i])
j++;
p[i] = j;
return p;
上述算法的问题在于它不适用于通配符。长话短说,考虑以下数学方程:
-
∵
a = b
∵b = c
∴a = c
当不涉及通配符时,这些等式是 100% 正确的。但是,它们不适用于通配符。例如:a = 1
、b = ??
(?? 是通配符)和c = 2
。 a equals b
和 b equals c
,但 a does not equal to c
由于通配符的这种怪异特性,上面提到的算法将不起作用!因此,我必须为通配符实现一个特定的算法。 我当前的实现如下所示:
vector<int> GeneratePrefixTable(vector<int> bytes, vector<unsigned char> flags)
vector<int> prefixTable(bytes.size());
prefixTable[0] = 0;
for (int j = 1, m = bytes.size(); j < m; j++)
int largest = 0;
for (int i = 1; i < j; i++)
bool match = true;
for (int k = 0; k < i; k++)
if (bytes[k] != bytes[j - i + k + 1] && !flags[k] && !flags[j - i + k + 1])
//if the bytes do not match and neither of them is a wildcard
match = false;
break;
if (!match)
continue;
largest = i;
prefixTable[j] = largest;
return prefixTable;
变量定义:
vector<int> bytes
模式。又名针。
vector<unsigned char> flags
标志数组,表示某个位置的字节是否是通配符
j
我们正在查看的模式的索引生成前缀#
largestOne
迄今为止发现的最大前缀长度
i
我们正在测试的前缀长度
请注意,一旦发现不工作的前缀长度,我并没有停止搜索。这也是由于通配符的奇怪属性。
例如,考虑模式01 02 ?? 02 00
:
-
长度为1:前缀:
1
后缀:0
,不匹配
长度为2:前缀:1 2
后缀:2 0
不匹配
长度为3:前缀1 2 ??
后缀:?? 2 0
匹配!
由于这个奇怪的属性,我必须测试每个可能的前缀长度。这进一步减慢了我的算法。有哪些方法可以加快我的前缀表生成算法?
【问题讨论】:
也许这会有所帮助:MoreKMP.pdf 或者这个:KMPWildcardMatch.java 上面链接下的“KMPWildcardMatch.java”不正确。失败的一个例子:s="abczzzdXzde"
,p = "abc???de"
。
【参考方案1】:
您混淆了两种类型。 “字符”类型比“搜索模式、字符或通配符”类型少一个元素。
这会导致您错误地认为“a”匹配“??” (通配符)。它没有。模式“a”匹配字符“a”,模式“??”匹配任何字符。明显不同的模式。
考虑正则表达式模式会有所帮助。 [ab]
与 [ba]
的模式相同; [0-9]
与[0123456789]
的模式相同,但a
绝对与.
的模式不同。
模式是传递相等的。同样,使用正则表达式样式:[abc]
= [acb]
= [bca]
。
KMP 要求您小心区分。给定当前匹配位置和匹配的前缀长度,您需要确定下一个可能的匹配位置。这不涉及模式平等。它涉及模式的交集。
Small sidestep:一个模式定义了一组要接受的字符串。两个模式可以说是有交集的,也就是都接受的字符串集合。对于复杂的模式,这很难计算。
实际上,KMP 将找到的搜索前缀与搜索的单词的移位版本进行比较。存储的值是两个模式具有非空交点的最小偏移。
【讨论】:
以上是关于使用通配符生成 Knuth–Morris–Pratt 前缀表的主要内容,如果未能解决你的问题,请参考以下文章
Knuth-Morris-Pratt 算法中的 DFA 构造
php Algoritma Knuth-Morris-Pratt
模板: 字符串模式匹配 Knuth–Morris–Pratt Algorithm
ZOJ 3957: Knuth-Morris-Pratt Algorithm