【问题标题】:Knuth–Morris–Pratt prefix table generation with wildcard使用通配符生成 Knuth–Morris–Pratt 前缀表
【发布时间】: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;
   }

上述算法的问题在于它不适用于通配符。长话短说,考虑以下数学方程:

  1. a = b
  2. b = c
  3. a = c

当不涉及通配符时,这些等式是 100% 正确的。但是,它们不适用于通配符。例如:a = 1b = ??(?? 是通配符)和c = 2a equals bb 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;
}

变量定义:

  1. vector&lt;int&gt; bytes 模式。又名针。
  2. vector&lt;unsigned char&gt; flags标志数组,表示某个位置的字节是否是通配符
  3. j 我们正在查看的模式的索引生成前缀#
  4. largestOne 迄今为止发现的最大前缀长度
  5. i 我们正在测试的前缀长度

请注意,一旦发现不工作的前缀长度,我并没有停止搜索。这也是由于通配符的奇怪属性。 例如,考虑模式01 02 ?? 02 00

  1. 长度为1:前缀:1后缀:0,不匹配
  2. 长度为2:前缀:1 2后缀:2 0不匹配
  3. 长度为3:前缀1 2 ??后缀:?? 2 0匹配!

由于这个奇怪的属性,我必须测试每个可能的前缀长度。这进一步减慢了我的算法。有哪些方法可以加快我的前缀表生成算法?

【问题讨论】:

  • 也许这会有所帮助:MoreKMP.pdf
  • 或者这个:KMPWildcardMatch.java
  • 上面链接下的“KMPWildcardMatch.java”不正确。失败的一个例子:s="abczzzdXzde"p = "abc???de"

标签: c++ algorithm wildcard string-search


【解决方案1】:

您混淆了两种类型。 “字符”类型比“搜索模式、字符或通配符”类型少一个元素。

这会导致您错误地认为“a”匹配“??” (通配符)。它没有。模式“a”匹配字符“a”,模式“??”匹配任何字符。明显不同的模式。

考虑正则表达式模式会有所帮助。 [ab][ba] 的模式相同; [0-9][0123456789] 的模式相同,但a 绝对与. 的模式不同。

模式是传递相等的。同样,使用正则表达式样式:[abc] = [acb] = [bca]

KMP 要求您小心区分。给定当前匹配位置和匹配的前缀长度,您需要确定下一个可能的匹配位置。这不涉及模式平等。它涉及模式的交集

Small sidestep:一个模式定义了一组要接受的字符串。两个模式可以说是有交集的,也就是都接受的字符串集合。对于复杂的模式,这很难计算。

实际上,KMP 将找到的搜索前缀与搜索的单词的移位版本进行比较。存储的值是两个模式具有非空交点的最小偏移。

【讨论】:

    猜你喜欢
    • 2014-06-09
    • 2014-02-21
    • 2015-08-05
    • 1970-01-01
    • 2014-05-01
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    相关资源
    最近更新 更多