KMP算法

模板
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
char q[N],a[N];
int ne[N];
int main()
{
    int n,m;
    cin>>n>>q+1>>m>>a+1;
    for(int i=2,j=0;i<=n;i++)
    {
        while(j&&q[i]!=q[j+1]) j=ne[j];
        if(q[i]==q[j+1]) j++;
        ne[i]=j;
     }
    for(int i=1,j=0;i<=m;i++) 
    {
        while(j&&a[i]!=q[j+1]) j=ne[j];
        if(a[i]==q[j+1]) j++;
        if(j==n)
        {
            cout<<i-n<<" ";
            j=ne[j];    
        }
        
    }
}
```

解决什么样的问题:

字符串匹配。给你两个字符串,寻找其中一个字符串是否包含另一个字符串,如果包含,返回包含的起始位置。 
如下面两个字符串:

char *str = "bacbababadababacambabacaddababacasdsd";
char *ptr = "ababaca";

str有两处包含ptr 
分别在str的下标10,26处包含ptr。

next数组:

考察 “ababaca”  

这里我们要计算一个长度为m的转移函数next。

next数组的含义就是一个固定字符串的最长前缀和最长后缀相同的长度。

比如:abcjkdabc,那么这个数组的最长前缀和最长后缀相同必然是abc。 
cbcbc,最长前缀和最长后缀相同是cbc。 
abcbc,最长前缀和最长后缀相同是不存在的。

**注意最长前缀:是说以第一个字符开始,但是不包含最后一个字符。 
比如aaaa相同的最长前缀和最长后缀是aaa。** 
对于目标字符串ptr,ababaca,长度是7,所以next[0],next[1],next[2],next[3],next[4],next[5],next[6]分别计算的是 
aababaababababaababacababaca的相同的最长前缀和最长后缀的长度。

由于aababaababababaababacababaca的相同的最长前缀和最长后缀是“”,“”,“a”,“ab”,“aba”,“”,“a”,所以next数组的值是[-1,-1,0,1,2,-1,0],这里-1表示不存在,0表示存在长度为1,2表示存在长度为3。这是为了和代码相对应。

 

 

 

如何预处理next数组:(借了acwing 上四谷夕雨的图 )

 

 

 此时我们就可以求出长度为i的子串中与最长前缀相等的最长后缀!

for(int i = 2, j = 0; i <= m; i++)
{
    while(j && p[i] != p[j+1]) j = next[j];

    if(p[i] == p[j+1]) j++;

    next[i] = j;
}

 

 

 

posted @ 2020-10-21 20:10  har74  阅读(85)  评论(0)    收藏  举报