KMP算法用于字符串匹配的问题,可以达到最好时间复杂度O(n+m)。其中n,m分别是文本串和模板串的长度。
传统的处理字符串匹配的方法是:遍历文本串的每一个字母,通过以这一个字母为开头的子字符串与模板串比较,当发现某一位不匹配时,跳出到执行下一个字母的检测。假设最坏情况,每一次都是模板的最后一个字母出错(比如文本串aaaaaaaaaaaab,模板串aaaab),需要的时间复杂度为O(n*m)。
KMP算法的精髓在于:对模板串进行预检测处理,当执行匹配时,发现了失配,那么可以充分利用预处理的结果跳过不必要的比较,直接在当前最为适配的位置进行比较。一个简单的例子,如果模板串是abcdef,当在‘e'位置比较时失配,我们可以知道此处文本串的前几个位置为”....abcd....“。从直觉上看,后面的几位都不应该再进行比较(不存在匹配)。所以模板串的预处理作用就是让程序拥有这种”直觉“。
预处理主要是对应模板串生成一个f[]数组,f取义为有限状态机(FSM)。
假如模板为temp[]
temp[]: a b c d a b g a b c f a
f[]: 0 0 0 0 1 2 0 1 2 3 0 1
f[]数组中非零项的数x表示当前位置的前x个字符与模板串的前x个字符相同。
有了f[]数组之后,就开始进行字符串的匹配。假如在模板串的(temp[7]=='g', f[7]=0)位置失配了,通过回看f[6]=='2',知道文本串此前两位为”ab“,与模板前两位一样,那么就可以将模板移到这里再重新开始比较,而之前前几位不可能存在匹配,就被跳过了。
前面提到的模板串
temp[]: a a a a b
f[]: 0 1 2 3 0
预处理函数
void handle_FSM(char* temp, int* tempFSM,int tempLen){
tempFSM[0] = 0 ;
for(int i = 1 ; i < tempLen ; i ++){
if(temp[i] == temp[tempFSM[i-1]]){
tempFSM[i] = tempFSM[i-1] + 1 ;
}else{
tempFSM[i] = 0;
}
}
}
匹配函数
void KMP(char* str, int strLen, char* temp, int* tempFSM, int tempLen){
int k = 0 ;
for(int i = 0 ; i <= strLen - tempLen ; ){
//match variable
bool match = true ;
for(int j = k ; j < tempLen ; j++){
if(temp[j] != str[i+j]){
if(tempFSM[j]){
i += j + 1;
k = 0 ;
}else if(j > 0 && tempFSM[j-1]){
i += j - tempFSM[j-1];
k = j ;
}else{
i += j + 1;
k = 0 ;
}
match = false;
break;
}
}
if(match){
cout << i << endl ;
if(tempFSM[tempFSM[tempLen-1]]){
i += tempLen - tempFSM[tempLen-1];
}else{
i += tempLen + 1 ;
}
k = 0 ;
}
}
}
-------------------————如有问题,请积极联系本人,谢谢-------------------------------------------