【问题标题】:String Matching: Computing the longest prefix suffix array in kmp algorithm字符串匹配:计算kmp算法中最长的前缀后缀数组
【发布时间】:2014-05-02 04:33:02
【问题描述】:

KMP algorithm for string matching。 以下是我在网上找到的用于计算最长前缀-后缀数组的code
定义:

lps[i] = the longest proper prefix of pat[0..i] 
              which is also a suffix of pat[0..i]. 

代码:

void computeLPSArray(char *pat, int M, int *lps)
{
    int len = 0;  // length of the previous longest prefix suffix
    int i;

    lps[0] = 0; // lps[0] is always 0
    i = 1;

    // the loop calculates lps[i] for i = 1 to M-1
    while(i < M)
    {
       if(pat[i] == pat[len])
       {
         len++;
         lps[i] = len;
         i++;
       }
       else // (pat[i] != pat[len])
       {
         if( len != 0 )
         {
           // This is tricky. Consider the example AAACAAAA and i = 7.
           len = lps[len-1]; //*****************

           // Also, note that we do not increment i here
         }
         else // if (len == 0)
         {
           lps[i] = 0;
           i++;
         }
       }
    }
}

我可以用len = len-1代替len = lps[len-1]吗?
因为 len 总是从 [0 .. someIndex] 开始计算前缀长度。那为什么在这里使用 lps 进行赋值呢?以下是我测试过哪些工作正常的案例(第一行是模式,随后两行是原始分配和修改后分配给 len 的结果):

a  a  a  b  a  b  c  
0  1  2  0  1  0  0  
0  1  2  0  1  0  0 

a  b  c  b  a  b  c  
0  0  0  0  1  2  3  
0  0  0  0  1  2  3  

a  a  b  c  b  a  b  
0  1  0  0  0  1  0  
0  1  0  0  0  1  0  

在此处编写两种变体的代码:http://ideone.com/qiSrUo

【问题讨论】:

    标签: c++ algorithm string-matching


    【解决方案1】:

    在它不起作用的情况下:

    i     0  1  2  3  4  5
    p     A  B  A  B  B  A 
    c1    0  0  1  2  0  1
    c2    0  0  1  2  2  3
    

    原因是:

    At i=4, len=2 
    p[i]='B' and p[len]='A' //Mismatch!
    lps string upto i=3: AB(0-1 prefix), (2-3 suffix)
    -------------------------------
    i=4
    Next charecter: B
    len=2 // longest prefix suffix length 
    Charecter looking for : A (=p[len])
    

    所以在 i=3 之前,我们将 AB(0-1) 作为与后缀 AB(2-3) 匹配的前缀,但现在在 i=4 处存在不匹配,所以我们看到我们可以' t 扩展原始前缀(0-1),因此要检查的位置是在“AB”之前找到的前缀,这是由 lps[len-1] 开始并且这不一定是 len-1,因为我们可能需要退后一步才能获得新的最长前缀后缀。

    【讨论】:

      【解决方案2】:

      这是我见过的最好的解释。其中的示例将清楚地回答您的问题。

      Knuth–Morris–Pratt(KMP) Pattern Matching(Substring search)

      【讨论】:

        【解决方案3】:

        这是我的 KMP 代码:-

        #include <bits/stdc++.h>
        using namespace std;
        
        
        int main(void){
            int t;
            scanf("%d",&t);
            while(t--){
                string s;
                cin>>s;
                int n = s.length();
                int arr[n];
                arr[0] = 0;
                int len = 0;
                for(int i = 1;i<n;){
                    if(s[len]==s[i]){
                        len++;
                        arr[i++] = len;
                    }
                    else{
                        if(len!=0){
                            len = arr[len-1];
                        }
                        else{
                            arr[i] = 0;
                            i++;
                        }
                    }
                }
                cout<<arr[n-1]<<endl;
            }
        
        
            return 0;
        }
        

        时间复杂度为 O(N)

        【讨论】:

          【解决方案4】:

          如果您也想了解该算法背后的直觉,请参阅 YouTube 上的以下视频。这是我对这个算法遇到的最清楚的解释。

          The longest prefix suffix array in kmp algorithm

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-12-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-10-05
            • 1970-01-01
            • 1970-01-01
            • 2015-10-25
            相关资源
            最近更新 更多