KMP
KMP 算法是一种字符串匹配算法,可以在
- 尽可能利用残余的信息,是KMP算法的思想所在;
- 如果把模式串视为一把标尺,在主串上移动,Brute-Force 就是每次失配之后只右移一位;KMP 算法则是每次失配之后,移很多位,跳过那些不可能匹配成功的位置。
前缀函数¶
KMP 算法是对前缀函数的一种应用。对前缀函数的定义:
给定一个长度为
- 如果子串
有一对相等的真前缀与真后缀: 和 ,那么 就是这个相等的真前缀(或者真后缀,因为它们相等:))的长度,也就是 ; - 如果不止有一对相等的,那么
就是其中最长的那一对的长度; - 如果没有相等的,那么
。
简单来说
用数学语言描述如下:
特别地,规定
朴素的暴力运算实现¶
- 在一个循环中以
的顺序计算前缀函数 的值( 被赋值为 ); - 为了计算当前的前缀函数值
,我们令变量 从最大的真前缀长度 开始尝试; - 如果当前长度下真前缀和真后缀相等,则此时长度为
,否则令 j 自减 1,继续匹配,直到 ; - 如果
并且仍没有任何一次匹配,则置 并移至下一个下标 。
vector<int> prefix_function(string s) {
int n = s.length();
vector<int> pi(n);
for (int i = 1; i < n; i++) {
for (int j = i; j >= 0; j--) {
// j 为前后缀的长度,从大到小尝试
if (s.substr(0, j) == s.substr(i - j + 1, j)) {
pi[i] = j;
break;
}
}
}
return pi;
}
使用动态规划优化的实现¶
优化的要点:
- 相邻的前缀函数值至多增加 1(在最好的情况下增加 1);
- 下一个前缀函数值要么增加 1,要么维持不变,要么减少;
前缀函数与 KMP 算法 - OI Wiki (oi-wiki.org) KMP算法 - 维基百科,自由的百科全书 (wikipedia.org) The Knuth-Morris-Pratt Algorithm in my own words - jBoxer (jakeboxer.com)