2模式字符串匹配算法

时间:2014-02-17 20:22:07

标签: regex string algorithm suffix-tree prefix-tree

我需要为最长的两个模式前缀/后缀匹配编码算法,其时间复杂度为O(n + m1 + m2),其中n是String的长度,m1,m2分别是pattern1和pattern2的长度

示例:如果字符串是“OBANTAO”而Pattern1是“BANANA”而Patten2是“SIESTA”,则答案是字符串的子字符串“BANTA”,其由BANANA的前缀BAN和SIESTA的后缀TA组成。

谷歌的结果是:“Rabin-karp string search algorithm”,“Knuth-morris-pratt algorithm”和“Boyer-moore string search algorithm”。

我能够理解以上3种算法,但问题是,它们都是基于“单一模式前缀/后缀匹配”。我无法为两个模式前缀/后缀匹配扩展它们。

示例算法或搜索它的链接对我开发程序非常有帮助。

2 个答案:

答案 0 :(得分:2)

Knuth - Morris - Pratt可以直接修改,为干草堆字符串中的每个位置产生针头串的最长前缀的长度,其匹配结束于该位置。使用KMP以字符串形式为Pat1计算此信息,在反向(字符串)中反向(Pat2),然后遍历String中的每个位置,查找最大前缀/后缀长度。

String =“OBANTAO”和Pat1 =“BANANA”以及Pat2 =“SIESTA”的示例:

"BANANA" = Pat1 in String
 O B A N T A O
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | |
| | | | | | | 0 ("")
| | | | | | 0 ("")
| | | | | 0 ("")
| | | | 3 ("BAN")
| | | 2 ("BA")
| | 1 ("B")
| 0 ("")
0 ("")

"ATSEIS" = reverse(Pat2) in reverse(String)
 O A T N A B O
^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | |
| | | | | | | 0 ("")
| | | | | | 0 ("")
| | | | | 1 ("A")
| | | | 0 ("")
| | | 2 ("AT")
| | 1 ("A")
| 0 ("")
0 ("")

反转第二个数组并按分数求和。

  0 0 1 2 3 0 0 0
+ 0 0 1 0 2 1 0 0
-----------------
  0 0 2 2 5 1 0 0
          ^
          |
         max (argument = "BAN" ++ reverse("AT"))

答案 1 :(得分:0)

我尝试用Java实现@David Eisenstat解决方案。 它在O(2n)时间和O(2(n + 1))辅助空间

String prefix = "BANANA";
    String suffix = "SIESTA";
    String input = "SABANANQS";

    // Prepare Inputs
    char[] prefixArray = prefix.toCharArray();
    char[] suffixArray = suffix.toCharArray();
    char[] inputArray = input.toCharArray();
    int inputLength = inputArray.length;
    int suffixLength = suffixArray.length;
    int prefixLength = prefixArray.length;
    // Auxiliary Spaces O(2(n+1))
    int[] prefixIndexs = new int[inputLength+1];
    int[] suffixIndexs = new int[inputLength+1];

    int m = 0;
    int n = 0;
    // O(1)
    for (int i = 0; i < inputLength; i++) {
        if (inputArray[i] == prefixArray[m]){
            m = m+1;
            prefixIndexs[i+1] = m;
            if (m == prefixLength) {
                m = 0;
            }
        }else{
            m = 0;
        }
        if (inputArray[inputLength-1-i] == suffixArray[suffixLength-1-n]){   // Reverse order or input and reverse oder of suffix
            n = n +1;
            suffixIndexs[i+1] = n;
            if (n == suffixLength) {
                n = 0;
            }
        }else{
            n = 0;
        }
    }

    int currmax =0;
    int mIndex = 0; // prefix Index from start
    int nIndex = 0; // suffix Index from End
    //O(1)  - Do Sum and find the max
    for (int i = 0; i < (inputLength+1); i++) {
        m = prefixIndexs[i];
        n = suffixIndexs[inputLength-i];
        if ( m != 0 && n != 0){  // if both prefix and suffix exists
            if (m+n > currmax){
                currmax = (m+n);
                mIndex = m;
                nIndex = n;
            }
        }
    }

    System.out.println("Input :"+input);
    System.out.println("prefix :"+prefix);
    System.out.println("suffix :"+suffix);
    System.out.println("max :"+currmax);
    System.out.println("mIndex :"+mIndex);
    System.out.println("nIndex :"+nIndex);
    System.out.println(prefix.substring(0,mIndex)+suffix.substring(suffix.length() - nIndex,suffix.length()));

不是将m和n重置为0,而是为每个实现KMP算法保留另一个数组,因为输入前缀和sufix没有重复的char序列我离开了它