【问题标题】:Algorithm for 2 Pattern String Matching2 模式字符串匹配算法
【发布时间】:2014-03-17 07:25:20
【问题描述】:

我需要编写一个最长的两个模式前缀/后缀匹配的算法,其时间复杂度为 O(n+m1+m2),其中 n 是字符串的长度,m1,m2 分别是模式 1 和模式 2 的长度.

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

来自 Google 的结果是:“Rabin-karp 字符串搜索算法”、“Knuth-morris-pratt 算法”和“Boyer-moore 字符串搜索算法”。

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

一个示例算法或搜索它的链接将对我开发程序有很大帮助。

【问题讨论】:

  • 它总是一个子字符串吗?还是子序列也可以?它总是前缀和后缀吗?例如在字符串lananaest - ananaest 是一个很好的解决方案,因为 anana 是香蕉的子字符串,而 est 是午睡的子字符串?
  • 这会给你带来什么实际的信息?
  • 你想匹配的模式总是(prefix of Pattern 1) + (suffix of pattern 2)吗?所以你真正想要的是由p1 + s2 组成的最长子串?您确实需要更好地说明您的问题。
  • @amit 对不起,不是那样,匹配的字符串应该始终是香蕉的剪辑前缀和午睡的剪辑后缀......即(B/BA/BAN/BANA/BANAN) 来自 BANANA 和 (A/TA/STA/ESTA/IESTA) 来自 SIESTA
  • 欢迎来到 StackOverflow!请在回答评论时更新您的问题(因为这意味着您的问题没有提供足够的信息),以便每个人都更清楚,并在必要时尝试使用代码标记使您的文本更具可读性。

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


【解决方案1】:

我尝试在 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 算法,因为输入的前缀和后缀没有重复的字符序列我离开了它

【讨论】:

    【解决方案2】:

    Knuth--Morris--Pratt 可以直接修改,以针对 haystack 字符串中的每个位置生成针字符串的最长前缀长度,匹配在该位置结束。使用 KMP 计算 String 中的 Pat1 和 reverse(String) 中的 reverse(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"))
    

    【讨论】:

    • 对不起,我没能明白你的意思。你能给我一个示例演示吗?
    • 我喜欢你的算法。只是想确定我是否输入了 BANABTA,那么你的算法选择 BANA(没有前缀)是可以接受的吗?
    • @Mani 我不知道,但不考虑至少一个数组为零的位置很容易。
    • @David Eisenstat.. 非常感谢..!!!它真的很有用,我用它做了一个实现。顺便说一句,现在我可以比较两种模式,如果有必要的话,我还会添加更多..!!!感谢所有回复的人。!!!
    猜你喜欢
    • 2014-08-20
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2011-09-08
    • 2018-10-04
    • 2016-01-08
    • 1970-01-01
    相关资源
    最近更新 更多