按照惯例,
今回是MOGE子镇楼。
今天是KMP算法,感觉理解还是不太扎实,写篇博客记录一下。
题目:
给定一个模式串 SS,以及一个模板串 PP,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模板串 PP 在模式串 SS 中多次作为子串出现。
求出模板串 PP 在模式串 SS 中所有出现的位置的起始下标。
第一行输入整数 NN,表示字符串 PP 的长度。
第二行输入字符串 PP。
第三行输入整数 MM,表示字符串 SS 的长度。
第四行输入字符串 SS。
共一行,输出所有出现位置的起始下标(下标从 00 开始计数),整数之间用空格隔开。
1≤N≤1051≤N≤105
1≤M≤1061≤M≤106
3
aba
5
ababa
0 2
暴力我们就不解释了,直接进入KMP。
KMP就是对字符串进行一系列匹配,从而减少不必要的操作,减小复杂度。
如何匹配呢,这就是我们的问题。KMP的做法就是找到字串的最大相同前后缀,从而进行匹配。
我们先写出我们能写出的代码:
#include<cstdio> const int maxn = 1e5 + 10; char S[maxn*10], P[maxn]; int main() { int ls, lp; scanf("%d%s", &lp, P+1); scanf("%d%s", &ls, S+1); return 0; }
我们要将P在S内作为子串出现的开始下标输出。
我们可以思考一下,我们在求字串最长相同前后缀时,和我们在求P在S内作为子串出现也是同一个问题。(此时P与S作为同一个字符串看待)
现在问题就是如何快速的求出字串最长相同前后缀。
所以我们令ne[n]为P中以第n位为结尾的字串最长相同前后缀。(只用对P串求字串最长相同前后缀)
所以我们又有代码:
int ne[maxn];
接下来就是求ne的过程了。
我们先贴出代码:
(P与S均于下标为1开始)
for (int i = 2, j = 0; i <= lp; ++i) { while (j && P[i] != P[j + 1])j = ne[j]; if (P[i] == P[j + 1])++j; ne[i] = j; }
在这里我们先扔出关于字串最长相同前后缀的定义:
假如A[]:abababf
看它的整体,则其
全部前缀为:
a,ab,aba,abab,ababa,ababab,ababab
全部后缀为:
f,bf,abf,babf,ababf,bababf,bababf
其前后缀长度不能为原串长
因此我们就有一个很明显的事实"ne[1]=0"。(至于为什么从i=2的原因,咱还没有搞(
我们以动态规划的视角观察这个东西,考虑能不能用ne[i-1]推出ne[i]。
ne[i]代表了以第i个字符结尾的字串最长相同前后缀大小。
当取到i时,也说明了前i个字符的字串也匹配成功,因此ne[0,i]有解。
---------------------------------------------------------------------
For()
{
我们设立一个指针j,j指向与ne[i-1]匹配的左串末尾。
因此我们也确保了有P[0,j]==P[i-1-j,i-1]。
(1)当P[j+1]==P[i]时:
有P[0,j+1]==P[i-j-1,i],也就是ne[i]=j+1;
break;
(2)当P[j+1]!=P[i]时:
也就没有P[0,j+1]==P[i-j-1],因此对于ne[i]的求解仍需要循环求解(此后j变为ne[ne[i-1]]匹配的左串末端),直至答案求出
(3)ne[i]=0;
}
---------------------------------------------------------------------
根据以上的思想,我们就可以得出以下代码:
#include<cstdio> const int maxn = 1e5 + 10; char S[maxn*10], P[maxn]; int ne[maxn]; int main() { int ls, lp; scanf("%d%s", &lp, P+1); scanf("%d%s", &ls, S+1); for (int i = 2, j = 0; i <= lp; ++i) { while (j && P[i] != P[j + 1])j = ne[j]; if (P[i] == P[j + 1])++j; ne[i] = j; } for (int i = 1, j = 0; i <= ls; ++i) { while (j && S[i] != P[j + 1])j = ne[j]; if (S[i] == P[j + 1])++j; if (j == lp) { printf("%d ", i - lp); j = ne[j]; } } return 0; }
原文:https://www.cnblogs.com/Inabameguru/p/14932861.html