KMP算法是实现在主串中查找子串第一次出现的位置的一个算法
这样的算法也可以通过暴力的方式解决,但是在极端情况下暴力算法会有很大的时间开销,因此KMP算法应运而生。
首先KMP算法是转而研究子串的而与需要寻找的主串无关了,因此在KMP算法中我们主要研究子串的构造,并通过研究子串构造出一个next数组作为回溯子串位置的依据(以此加快子串的滑动从而防止了主串的回溯,很大程度上优化了程序的时间复杂度)
KMP算法的主要原理就是在匹配的过程中减少不必要的比对,从而减少计算次数降低时间复杂度
其中next数组的含义就是,当子串的第k个字符与主串发生错误匹配时,跳到子串的next[j]位置重新与主串当前位置进行比较
next数组的程序求解如下所示:
void solve_next(char t[], int l1) {
int i = 1, j = 0;
next[1] = 0;
while(i < l1) {
if(!j || t[i] == t[j]) {
i++, j++;
next[i] = j; //满足条件,next[j+1] = next[j] + 1
}
else
j = next[j]; //继续寻找
}
}
查找子串的算法的实现就很简单了
#include <iostream>
const int N = 5005;
int l1, l2; // record length of tem and ss
char tem[100] ; //模式串
char ss[100] ; // main string
int next[N];
void solve_next(char t[], int l1) {
int i = 1, j = 0;
next[1] = 0;
while(i < l1) {
if(!j || t[i] == t[j]) {
i++, j++;
next[i] = j; //满足条件,next[j+1] = next[j] + 1
}
else
j = next[j]; //继续寻找
}
}
int Index_KMP(char s[], char t[], int l1, int l2) {
int i = 1, j = 1;
while(i <= l2 && j <= l1) {
if(!j || s[i] == t[j]) {
i++; j++;
} else
j = next[j]; // 滑动模式串
}
if(j > l1)
return i - l1; // 匹配成功
return -1;
}
int main() {
std::cin >> l1 >> tem+1;
std::cin >> l2 >> ss+1;
solve_next(tem, l1);
for(int i = 1; i <= l1; ++i) {
std::cout << next[i] << ' ';
}
std::cout << std::endl;
int index = Index_KMP(ss, tem, l1, l2);
std::cout << index;
return 0;
}