KMP算法(字符串查找算法)
算法思想:
利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置。
算法流程:
假设现在在文本串s匹配到i位置,模式串p匹配到j位置:
1.如果j=-1,或者当前字符匹配成功(即s[i]==p[j]),都令i++,j++,继续匹配下一个字符;
2.如果j!=-1,并且当前字符匹配失败(即s[i]!=p[j]),都令i不变,j=next[j]。
当匹配失败时,j要移动的下一个位置k。存在着这样的性质:最前面的k个字符和j之前的最后k个字符是一样的。因此next[j]的值(也就是k)表示,当s[i]!=p[j]时,j指针的下一步移动位置。
next数组含义:表示当前字符之前的字符串中,有多大长度的相同前缀后缀。
核心代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int* GetNextval(char* p);
int KmpSearch(char* s, char* p){
int i = 0;
int j = 0;
int slen = strlen(s);
int plen = strlen(p);
cout << "slen = " << slen << endl;
cout << "plen = " << plen << endl;
int* next = GetNextval(p);
while(i < slen && j < plen){
if(j == -1 || s[i] == p[j]){
i++;
j++;
}else{
j = next[j];
}
cout << "i = " << i << ", j = " << j << endl;
}
cout << "i = " << i << endl;
cout << "j = " << j << endl;
if(j == plen)
return i - j;
else
return -1;
}
int* GetNextval(char* p){
int plen = strlen(p);
int* next = new int[plen];
next[0] = -1;
int k = -1;
int j = 0;
while(j < plen - 1){
if(k == -1 || p[j] == p[k]){
j++;
k++;
if(p[j] != p[k])
next[j] = k;
else //当两个字符相等时要跳过
next[j] = next[k];
}
else{
k = next[k];
}
}
cout << "-------next数组--------" << endl;
for(int m = 0; m < plen; m++){
cout << next[m] << " ";
}
cout << endl;
cout << "-----------------------" << endl;
return next;
}
int main(){
char* s = "abcdefg";
char* p = "bcd";
int result = KmpSearch(s, p);
cout << "字符串匹配的起始位置为: " << result << endl;
return 0;
}
如果文本串的长度为n,模式串的长度为m,那么匹配过程的时间复杂度为O(n),算上计算next数组的O(m)时间,KMP的整体时间复杂度为O(m+n)。
这位博主大佬分析的比较通俗易懂,推荐给大家:
https://www.cnblogs.com/yjiyjige/p/3263858.html