KMP
KMP
定义
若要在 abcbdbddd中寻找cdb则有
模式串\(S\):cdb
目标串\(T\):abcbdbddd
\(i\)为目标串指针(i=1开始)
\(j\)为模式串指针(j=1开始)
BF(暴力算法)
BF算法是一个普通的暴力匹配算法,其算法思想是先将目标串的第一位与模式串的第一位先进行匹配。若成功,则将匹配模式串与目标串的第二位,若不相等,则将匹配目标串的第二位与模式串的第一位。
模拟一下:
目标串:abeabeabas
模式串:abeabas
但是睿智的你肯定已经发现了,当我们在匹配失败时,没有必要将\(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)\) 继续比较。
举个例子:
但是若\(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];
}
可能算法讲解有些迷糊,主要靠各位大佬们自行多次反复理解。

浙公网安备 33010602011771号