KMP
kmp算法就是字符串匹配算法,输入两个字符串,检测字符串b是不是字符串a的子串。
前言
这个算法不太好理解,这里a是主串,b是子串。
一、next数组的设置
- next数组长度与字串相同
- next用于计算
相似度
- 单字符
相似度
是0
void test(int* next, const string& b) {//这里const string& b可以简写为string b。
//单字符从0开始
next[0] = 0;
int j = 0;
for (int i = 1; i < b.size(); i++) {
while (j > 0 && b[i] != b[j])
j = next[j - 1];
if (b[i] == b[j])
j++;
next[i] = j;
}
}
如果b=ababa
。那么next数组就是00123。什么意思呢?不急,听我慢慢说。
next[3]=2:我这里有两个字符与b前两个字符一致。
next[4]=3:我这里有两个字符与b前三个字符一致。
到这里,咱们算是把next数组初始化了,后面会有用
二、开始匹配
int Strstr(string a, string b) {
if (b.size() == 0)//如果子串是空,直接返回
return 0;
int* next = new int[b.size()];
test(next, b);//初始化next
int j = 0;
for (int i = 0; i < a.size(); i++) {
while (j > 0 && a[i] != b[j])
j = next[j - 1]; //关键
if (a[i] == b[j])
j++;
if (j == b.size())
return i-b.size()+1+1;//返回所要匹配的位置
}
return -1;
}
这里讲一下关键点:
if (a[i] == b[j])
j++;
如果字符相等,咱们j就加1,加到j==b.size()
,就说明匹配成功!
接下来是最关键的一点:
while (j > 0 && a[i] != b[j])
j = next[j - 1]; //关键
- j是在副串上游走的。
- 当发现
a[i]!=b[j]
时,游走的j作废,给j赋值next[j-1]
,一直循环,直到a[i]==b[j]
。 a[i]==b[j]
之后,j++,表明当前a[i]位置,有j个字符与副串匹配。- 当
j==b.size()
时,说明a[i]位置,往前数j位,与b匹配,匹配成功。
总结
所有代码:
#include<iostream>
#include<string>
using namespace std;
void test(int* next, const string& b) {
//单字符从0开始
next[0] = 0;
int j = 0;
for (int i = 1; i < b.size(); i++) {
while (j > 0 && b[i] != b[j])
j = next[j - 1];
if (b[i] == b[j])
j++;
next[i] = j;
}
}
int Strstr(string a, string b) {
if (b.size() == 0)
return 0;
int* next = new int[b.size()];
test(next, b);
int j = 0;
for (int i = 0; i < a.size(); i++) {
while (j > 0 && a[i] != b[j])
j = next[j - 1]; //关键
if (a[i] == b[j])
j++;
if (j == b.size())
return i-b.size()+1+1;
}
return -1;
}
int main() {
string a, b;
cin >> a >> b;
int i = Strstr(a, b);
if (i) {
cout << "匹配成功!"<<"位置是:"<<i << endl;
}
else {
cout << "匹配失败!" << endl;
}
return 0;
}