字符串算法总结(kmp&&manacher&&trie&&AC自动机)

更博的目的是让自己学会AC自动机qwq

我太菜了连AC自动都不会qwq


KMP算法:

\(KMP\) 算法可以在线性时间内完成字符串匹配,对于每次失配之后,都不会从头重新开始枚举,而是根据已经得知的数据,从某个特定的位置开始匹配;而对于模式串的每一位,都有唯一的“特定变化位置”,这个在失配之后的特定变化位置可以帮助我们利用已有的数据不用从头匹配,从而节约时间。

具体操作也很简单,首先预处理出一个 \(nex\) 数组,\(nex[i]\) 表示模式串的\(i\) 位往前 \(nex[i]\)模式串第一位往后 \(nex[i]\)相同,注意此处 \(nex[i]\ !=i\) 。比如:

模式串:ababacbab
         ababacbab
所以nex[5]=3

那么,这个数组有什么用呢?举个栗子:

模式串:ababacbab
文本串:abababacbab

传统做法是失败就从头开始:

文本串:abababacbab
已匹配:ababac  -->失败

文本串:abababacbab
已匹配: a  -->失败

文本串:abababacbab
已匹配:  ababacbab  -->成功

但是如果有着这个 \(nex\)

文本串:ab(aba)bacbab
已匹配:(aba)bac  -->失败

由于到第五位都是成功匹配,且nex[5]=3
所以我们可以直接从模式串的第三位开始

文本串:ab(aba)bacbab
已匹配:  (aba)bacbab  -->成功&&括号内的无需重新匹配

所以只要我们有了 \(nex\) 数组就可以提速了,另外如果需要从头开始,那么 \(nex\) 的值为 0 。

如何求出 \(nex\) 数组?具体解释见代码:

//核心思路就是自己和自己匹配
for(int i=2,j=0;i<=n2;i++)
{//i=2是因为要从模式串的第二位开始尝试和第一位匹配
 //j代表往前匹配了多少位
    while(j>0&&b[i]!=b[j+1]) j=nex[j];
    //匹配失败就往前跳,直到j=0
    if(b[i]==b[j+1]) j++;//成功就+1
    nex[i]=j;
}

匹配文本串和模式串也是一样的

for(int i=1,j=0;i<=n1;i++)
{//i要从文本串的第一位开始尝试
 //j代表模式串往前匹配了多少位
    while(j&&a[i]!=b[j+1]) j=next[j];//同上
    if(a[i]==b[j+1]) j++;//成功就+1
    if(j==n2){}//即模式串往前n2位都已匹配
}

最后附上模板题和代码:

P3375 【模板】KMP字符串匹配

#include<bits/stdc++.h>
using namespace std;
long long next[1000001],n1,n2;
char b[1000001],a[1000001];
int main(){
    scanf("%s %s",a+1,b+1);
    next[1]=0;
    n1=strlen(a+1);
    n2=strlen(b+1);
    for(int i=2,j=0;i<=n2;i++)
    {
        while(j>0&&b[i]!=b[j+1]) j=next[j];
        if(b[i]==b[j+1]) j++;
        next[i]=j;
    }
    for(int i=1,j=0;i<=n1;i++)
    {
        while(j&&a[i]!=b[j+1]) j=next[j];
        if(a[i]==b[j+1]) j++;
        if(j==n2) cout<<i-n2+1<<endl;
    }
    for(int i=1;i<=n2;i++) cout<<next[i]<<" ";
    return 0;
}

其余的先咕着qwq

猜你喜欢

转载自www.cnblogs.com/ajy-shi-cj-zui-cai/p/10546839.html