扩展kmp--模板解析

扩展kmp:

  用于求串的各个后缀与原串的最长公共前缀的长度;

上图的是字符串自匹配的过程:

图一:

    假设现在匹配到i-1了,开始求next [ i ] 的值,此时,k记录的是到目前为止匹配到的最远的位置的那一次的起点,p标志的是已经匹配过的最远的点;

图二:

    因为前面是匹配过的,所以可以知道,k~p和源串的1~b是一模一样的,所以 i 匹配的前一段可以和k~p段直接匹配,而不用和源串匹配,如果i匹配完成后,从i开始next[ i ]长度是和源串一模一样的。这个时候可以看图三。

图三:

    可以看到 i 与 k 的相对位置和a 与 1 的相对位置是一样的,而且1~a与k~i之间的是一样的,i与a也是一样的,而且next[ a ]是已经计算过的,所以用l = next[ i - k ]

p=k+next[ k ];   然后  if ( l<p)就是当用之前的匹配结果没有匹配超出p那么就可以直接用之前的结果了:next[ i ]=l;如果超出了p的范围,就要把超出的部分匹配一下,然后要更新k;

这样自匹配就结束了;

然后是字符间匹配,过程几乎一模一样;不再详述;

代码如下;

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 string a,b;//a串和b的所有后缀匹配可以匹配的最长长度;
 5 int m,n;//m,是a串的长度;n是b串的长度;
 6 int Next[100000],ret[100000];//Next数组是自匹配,ret是串间匹配;
 7 
 8 void ExtendKmp()
 9 {
10     int i,j,k;
11     for( j=0;j+1<m&&a[j]==a[j+1];j++);
12     Next[1]=j;
13     k=1;
14     for( i=2;i<m;i++)
15     {
16         int p=k+Next[k],l=Next[i-k];
17         if(l+i<p)
18             Next[i]=l;
19         else
20         {
21             for(j = max(0,p-i);j<m&&i+j<m&&a[j]==a[i+j];j++);
22             Next[i]=j;
23             k=i;
24         }
25     }
26     for(j=0;j<n&&j<m&&a[j]==b[j];j++);
27     ret[0]=j;
28     k=0;
29     for( i=1; i<n; i++)
30     {
31         int p=k + ret[k],l=Next[i-k];
32         if(l+i<p)
33             ret[i]=l;
34         else
35         {
36             for(j =max(0,p-i);j<m&&i+j<n&&a[j]==b[i+j];j++);
37             ret[i]=j;
38             k=i;
39         }
40     }
41 }
42 
43 int main()
44 {
45     cin>>a>>b;
46     m=a.size();
47     n=b.size();
48     ExtendKmp();
49     for(int i=0;i<n;i++)
50         cout<<ret[i]<<' ';
51     cout<<endl;
52     return 0;
53 }
原文地址:https://www.cnblogs.com/by-1075324834/p/4525743.html