KMP

KMP

定义

若要在 abcbdbddd中寻找cdb则有

模式串\(S\)cdb

目标串\(T\)abcbdbddd

\(i\)为目标串指针(i=1开始)

\(j\)为模式串指针(j=1开始)

BF(暴力算法)

BF算法是一个普通的暴力匹配算法,其算法思想是先将目标串的第一位与模式串的第一位先进行匹配。若成功,则将匹配模式串与目标串的第二位,若不相等,则将匹配目标串的第二位与模式串的第一位。

模拟一下:

目标串:abeabeabas

模式串:abeabas

\[\begin{align}&第一次\\ &{\color{Red}a}beabeabas\\ &{\color{Red}a}beabas\\ \end{align} \]

\[\begin{align}&第二次\\ &a{\color{Red}b}beabeabas\\ &a{\color{Red}b}eabas\\ \end{align} \]

\[\begin{align}&第三次\\ &ab{\color{Red}e}abeabas\\ &ab{\color{Red}e}abas\\ \end{align} \]

\[\begin{align}&第四次\\ &abe{\color{Red}a}beabas\\ &abe{\color{Red}a}bas\\ \end{align} \]

\[\begin{align}&第六次(中间跳了几次)\\ &abeab{\color{Red}e}abas\\ &abeab{\color{Red}a}s\\ &失败匹配 \end{align} \]

\[\begin{align} &第七次\\ &a{\color{Red}b}eabeabas\\ &{\color{Red}a}beabas \end{align} \]

但是睿智的你肯定已经发现了,当我们在匹配失败时,没有必要将\(i\)又重新回到\(1\),完全可以将\(j=3\) 与其继续比较,这是因为\(j=6\)时,\(S[1,2]=S[4,5]\),反正到此时已经保证\(T\)串的\(1\) ~ \(j-1\)已经匹配。

由此我们在这里引入\(border\)

border

定义:指的是字符串\(T\),在第\(i\)位时,\(T[1,i]\)中最长的前缀与后缀相同的长度(不包括串本身)。

举例:有\(T=aba\) ,则有\(border[1]=0,border[2]=0,border[3]=1\)

根据定义可以得到当\(S\)\(T\)匹配时,在第\(S[i],T[j]\)匹配失效时,\(j\)可以回到\(border[j-1]+1(j~!=1)\) 继续比较。

举个例子:

\[S=ababababe\\ T=ababe\\ 当i=5,j=5时匹配失败\\ 则可以保持i不变,j=border[j-1]+1=3以继续匹配 \]

但是若\(border[j-1]+1=1\) 则应当将\(i++\) 以继续比较

接下来便有一个问题,怎么快速求出\(border\)

可以观察,假设我们已经求出了\(border[1-i]\),要求\(border[i+1]\),怎么办?

显然我们可以令\(j=border[i]\)

\(S[j+1]=S[i+1]\)\(border[i+1]=j+1\)

反之,则继续上面的步骤,直到有成功的,或者\(j=0\)(无满足的前缀与后缀)

并且显然有\(border[1]=0\)

所以有以下代码:

char S[maxn];
int border[maxn];
inline void getborder(){
    int j=0;
    border[1]=0;
    for(int i=2;i<=ls;i++){
        while(j&&S[i]!=S[j+1]) j=border[j];
        if(S[i]==S[j+1]) j++;
        border[i]=j;
    }
}

KMP(看毛片)

算法流程:

先计算出\(border\),当然在其他题解里面可能是\(next\)

再依次匹配\(S,T\)

每次匹配时,\(j\)表示\(S\)匹配位的上一位,\(i\)表示\(T\)匹配位的下标。

那么当S[j+1]!=T[i]&&j!=0时,一直取\(j=border[j]\)

若有\(S[j+1]==T[i]\) ,则\(j++,i++\)

反之只有\(i++\)

CODE

    j=0;
    for(int i=1;i<=la;i++){
        while(j&&a[i]!=b[j+1]) j=p[j];
        if(a[i]==b[j+1]) j++;
        if(j==lb) write(i-lb+1),j=p[j];
    }

可能算法讲解有些迷糊,主要靠各位大佬们自行多次反复理解。

posted @ 2022-08-02 09:31  轩Demonmaster  阅读(62)  评论(0)    收藏  举报