KMP模式匹配
字符串从下标0开始存
求模式串s是否是主串p的一个子串,若是,输出在主串中的下标
暴力匹配
- 一个指针
i记录匹配过程中主串中的下标,一个指针j记录匹配过程中子串中的下标,一个指针k记录主串中开始匹配的下标 - 当从
k开始匹配的子串匹配失败,k加一,再以k为起点开始匹配
int simple(const string& str,const string& substr){
int k=0;
int i=k;
int j=0;
while(i<str.length()&&j<substr.length()){
if(str[i]==substr[j]){
i++,j++;
}
else { //子串匹配失败,从k+1开始重新匹配
j=0;
k++;
i=k;
}
}
if(j==substr.length()){ //substr遍历完了,匹配成功
return k;
}
else return -1; //没找到返回-1
}
时间复杂度\(O(L_{1}L_{2})\)
KMP算法
本质是对暴力的优化
暴力匹配中的i在失配后需要回溯到上一个匹配起点k的下一个位置,重新开始匹配
思路
当i失配时:从k+1开始重新匹配(暴力)
- 从某个大于
k的下标到上一次失配的下标i的上一个字符都匹配上了,又会再次匹配i位置 - 从
k+1到i的上一个下标都失配,又会再次从i开始匹配
所以最终还是会走到i位置
优化:i不回溯,让j回溯到一个合适的位置
最长相同前后缀:一个字符串的前缀子串和后缀子串相同,且符合条件的子串最长
比如abcdhabc的最长相同前后缀是abc
假设在主串的i,模式串的j失配,此时模式串的下标0`j-1`和主串的下标`i-j`i-1是完全相同的,假设这个子串的最长相同前后缀长度为len,模式串的下标0`len-1`和主串的下标`i-len`i-1是完全相同的,所以j该回溯的位置是len,该位置与主串p无关,所以需要求出模式串s每个前缀子串的最长相同前后缀的长度
用数组next记录next[j]应该回溯的位置,也就是模式串的下标0~j-1的最长相同前后缀的长度,也就是模式串的长度为j的前缀子串的最长相同前后缀的长度
求next数组
动态规划思想
next[0]=-1,next[1]=0,-1作为非法值
假设已知0~j-1的next值,要求next[j]
设next[j-1]=a,即模式串s的0~j-2的前缀子串的最长相同前后缀的长度为a,此时需要比较(匹配)j-1位置和a位置,相当于模式串自己匹配自己
- 若
s[a]==s[j-1],则模式串s的0~j-1的前缀子串的最长相同前后缀的长度为next[j-1]+1,即a+1 - 若
s[a]!=s[j-1],相当于失配,a回溯到next[a],重新匹配
实现
void getNext(){
nex[0]=-1;
nex[1]=0;
int j=2; //要求nex的下标
int a=nex[1];
while(j<ls){
if(a==-1||s[j-1]==s[a]){
s[j]=a+1;
j++,a++;
}
else { //匹配失败,需要a回溯
a=nex[a];
}
}
}
int KMP(string& p,string& s){
getNext();
int lp=p.length(); //主串长度
int ls=s.length(); //模式串长度
int i=0,j=0;
while(i<lp&&j<ls){
if(j==-1||p[i]==s[j]){
i++,j++;
}
else { //失配
j=nex[j];
}
}
if(j>ls)cout<<i-ls<<endl;
else cout<< -1 <<endl;
}
时间复杂度\(O(L_{1}+L_{2})\)
最短相同前后缀
有三个长度分别为ls,lt,lr的字符串s,t,r,且 \(ls<lt<lr\)
结论:
- 若
s是t的相同前后缀,t是r的相同前后缀,则s是r的相同前后缀 - 若
s是r的相同前后缀,t是r的相同前后缀,则s是t的相同前后缀
要找长度为a的前缀子串的最小相同前后缀的长度
长度为a的前缀子串最长相同前后缀长度为nex[a],依次迭代,直到nex[a]为0或-1,此时的a就是要求的最短相同前后缀
int solve(int a){
while(nex[a]!=0&&nex[a]!=-1)a=nex[a];
return a;
}
循环字符串
循环字符串s由字符串r循环复制得到,且r不为循环字符串
比如:s="abcabcabcabc",r="abc"
则循环字符串s的最小循环节长度(r的长度)为n-nex[n]
任何一个字符串都可以看成是循环字符串的前缀子串

所以若字符串s是某个循环字符串的前缀子串,这个循环字符串的最小循环节也为n-nex[n]

浙公网安备 33010602011771号