KMP模式匹配算法改进:https://blog.csdn.net/TinnCHEN/article/details/93472761
意义:当子串有多个相同部分时,与朴素模式匹配算法相比,大大减少了循环次数。时间复杂度由O((n-m+1)*m)变为O(n+m)。
重点:对用于匹配的子串的next数组的构建。next数组表示若当前位不匹配我们该从第几位开始重新比较。
next数组举例说明:
我们用 j 来表示子串中第几位,为方便我们从1开始计数。
eg1:当子串无重复时
子串abcdx
1、j = 1,next[1] = 0;
2、j = 2, j到j -1 之间为a,因此只有一位next[2] = 1;
3、j = 3, j到j -1 之间为ab, 且 a != b, 因此next[3] = 1;
…
我们可以得到next数组01111。
eg2: 当子串有重复时
子串:abcabx
1、j = 1,next[1] = 0;
2、j = 2, j到j -1 之间为a,因此只有一位next[2] = 1;
3、j = 3, j到j -1 之间为ab, 且 a != b, 因此next[3] = 1;
4、j = 4, j到j -1 之间为abc, 且 a != c, 因此next[4] = 1;
5、j = 5, j到j -1 之间为abca, 且 a == a, 因此next[5] = 2;
6、j = 6, j到j -1 之间为abcab, 且 ab == ab, 因此next[6] = 3;
具体代码实现:
void GetNext(string t, int *next){
int i,j;
i = 1; //i表示后缀中最新需要比较的字符
j = 0; //j表示前缀中需要与后缀i比较的字符
next[1] = 0;
/*
情况1:j == 0,
除了第一次进入循环意味着最新的比较位与前缀任一位置均不相同,
j回溯到了next[1]。
情况2:t[i] == t[j], 意味着i与前缀中的某一位j匹配上了,
所以若下一个i(也就是代码中的++i)在匹配过程中发生了不匹配现象,
可以直接从前缀的下一位(++j)处重新进行匹配,不用从头匹配。
*/
while( i < t.size()){
if( j == 0 || t[i] == t [j]){
++i;
++j;
next[i] = j;
}
else
j = next[j]; //若不相等,则跳转到上一回溯位置看是否相等。
}
}
int Pos_KMP(string s, string t, int pos){
int i = pos;
int j = 1;
int next[1000];
GetNext(t, next);
while(i <= s.size() && j <= t.size()){
if( j == 0 || s[i] == s[j]){
++i;
++j;
}
else
j = next[j]; //此处是与朴素模式匹配算法不同处,不用每次都从第一位开始比较
}
if( j > t.size())
return i - t.size();
else
return 0;
}