所谓KMP算法:
核心便在前缀表,前缀表的概念又是什么,举个例子:字符串"ababd"的前缀表怎么求?
- 对 "a"求前缀,因为是首位所以没有前缀相同的可能,所以标记为-1,特殊处理。
- 对 “ab” 求前缀, 前缀就是’a’,所以没有相同前缀,标记为0(相同前缀的长度)。
- 对 “aba” 求前缀, 前缀就是’ab’,因为’a’ 和’ b’不同,所以标记为0(相同前缀的长度)。
- 对"abab"求前缀, 前缀就是’aba’,因为’a’ 和’ a’相同,所以标记为1(相同前缀的长度)。
- 对"ababd"求前缀, 前缀就是’abab’,因为’ab’ 和’ ab’相同,所以标记为2(相同前缀的长度)。
前缀表实现代码
int nextj[N];
void GetNext(string str) {
int k = 0;
nextj[0] = -1; //第一个永远没有前缀
nextj[1] = 0; //前缀永远只有一个,无法重复
for (int i = 2; i < str.length(); i++) { //这个过程类似动态规划
if (str[i - 1] == str[k]) nextj[i] = ++k;
else if (k == 0) nextj[i] = 0;
else {
k = nextj[k];
i--;
}
}
}
运用前缀表的搜索过程
实验代码
#include<iostream>
#include<string>
#define N 1000
using namespace std;
int nextj[N];
void GetNext(string str) {
int k = 0;
nextj[0] = -1;
nextj[1] = 0;
for (int i = 2; i < str.length(); i++) {
if (str[i - 1] == str[k]) nextj[i] = ++k;
else if (k == 0) nextj[i] = 0;
else {
k = nextj[k];
i--;
}
}
}
int main() {
bool notFind = true;
int j = 0;
int index = 0;
string a = "ababababcdababd";
string b = "ababd";
GetNext(b);
while (index < a.length())
{
if (j == -1) {
index++;
j++;
}
else if (a[index] == b[j]) {
if (j == b.length() - 1) {
cout << index - b.length() + 1 << endl;
notFind = false;
break;
}
index++;
j++;
}
else {
j = nextj[j];
}
}
if (notFind) cout << "notFind" << endl;
return 0;
}
效果展示
若把查找的字符串改为"abcde"
时间仓促,下次补充。