扩展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 }