考研不要求写代码但要会手算next[j]以及知道nextval[ ]优化方法
思路:
BF(朴素模式匹配)
朴素的模式匹配算法:
直接进行搜索匹配。基本思想是:从主串S的第一个字符开始和模式T的第一个字符进行比较,若相等,则继续比较两者的后续字符;否则,从主串S的第二个字符开始和模式T的第一个字符进行比较。重复上述过程,若T中的字符全部比较完毕,则说明本趟匹配成功;否则匹配失败。
KMP算法:
主串指针不回退,每次匹配失败时只回退模式串的指针
用next数组来标记模式串回退的位置,当发现字符不匹配时,模式串指针(j)回溯到j=next[j]
特殊情况当j=next【j】=0时该怎么办?
next数组:
怎么求?
next[ j ]=由下标为1~j-1的字符组成的字符串中最长的相等前后缀长度+1
例如下图中j=6,next[6]怎么求?
先将下标1~5的字符取出来构成字符串a b a b a
最长的前后缀相等字符串为 a b a ->next [6]=3+1=4;
特别的:next【1】=0和next【2】=1是固定的
代码实现:
//这里传入的字符串为"#abc....."
void get_next(string t, vector<int> &next) {//只和模式串(字串)有关系
int i = 1, j = 0;
next[1] = 0;
int tlen = t.length() - 1;
while (i < tlen)
{
if (j == 0 || t[i] == t[j]) {
++i;
++j;
next[i] = j;
}
else {
j = next[j];
}
}
}
优化
以下动图演示了使用next【j】原理导致出现重复操作的情况
这种情况下我们可以使用nextval【j】数组进行优化:
代码实现:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//BF模式匹配
int index(string s, string t, int pos) {
s = '#' + s, t = '#' + t;
int j = 1;
int i = pos;
int slen = s.length() - 1;
int tlen = t.length() - 1;
while (i <= slen && j <= tlen)
{
if (s[i] == t[j]) {
++i;
++j;
}
else {
i = i - j + 2;
j = 1;
}
}
if (j > tlen)return i - tlen;
else return 0;
}
//这里传入的字符串为"#abc....."
void get_next(string t, vector<int> &next) {//只和模式串(字串)有关系
int i = 1, j = 0;
next[1] = 0;
int tlen = t.length() - 1;
while (i < tlen)
{
if (j == 0 || t[i] == t[j]) {
++i;
++j;
next[i] = j;
}
else {
j = next[j];
}
}
}
//这里传入的s,t是最长输入的字符串
int index_kmp(string s, string t, int pos) {
//为了下标表示方便,我们需要在字符串加上一个"#",这里加什么都行,目的只是为了字符串下标从1开始
s = '#' + s, t = '#' + t;
//从头开始,取i=1
int j = 1; int i = pos;
//next[ ]数组的长度=t.length()
vector<int >next(t.length());
get_next(t, next);
//slen的长度就是没加"#"前的长度
int slen = s.length() - 1;
int tlen = t.length() - 1;
while (i <= slen && j <= tlen)
{
if (s[i] == t[j] || j == 0) {
++i;
++j;
}
else {
j = next[j];
}
}
//下标从1开始,假如下标从0开始对应i-tlen-1
if (j > tlen) return i - tlen;
else return -1;
}
int main()
{
string s;
string t;
int pos;
//输入不需要在前面加"#"。
cout << "请输入主串:";
cin >> s;
cout << "请输入子串:";
cin >> t;
cout << "请输入搜索起始位置:";
cin >> pos;
//cout << "BF模式匹配:" << index(s, t, pos) << endl;
cout << "KMP模式匹配:" << index_kmp(s, t, pos) << endl;
}