串的模式匹配算法
在kmp算法中,主串的指针不需要再回退,模式串字符不等于主串时,指针j根据next数组回退至next[j]。
求解next数组
原理(参考严蔚敏版数据结构):
通过递推的方式得到,如图为模式串
当已知红色区与蓝色区已经匹配时,求next[j]:
1)若s[i]==s[j]
next[j+1]=next[j]+1;
2)当s[i]!=s[j]
可将next数组求值理解成在模式串中求字串的问题;
故next[j]=next[i]+1;
当然这种方式求出的next数组还可以更新为nextval数组,具体参考数据结构部分。
算法题直接背模板。
严蔚敏数据结构书中求next和nextval数组的判断条件及边界问题难以记忆,故我在这里参考了网上的其他代码,整体思路一致,只是next[i]数组变成当i+1与j不匹配时i应回退的位置(这与408要求的next数组不同),故在求next数组时应存在p[next[i]]==p[i]。
a b c a b
下标 1 2 3 4 5
next[ ] 0 0 0 1 2
给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 P在字符串 S 中多次作为子串出现。
求出模式串 P 在字符串 S中所有出现的位置的起始下标。
#include<algorithm>
#include<iostream>
using namespace std;
const int N = 1e7+10;
char s[N], p[N];
int ne[N];
int n, m;
int main()
{
cin >> n >> p + 1 >> m >> s + 1;
//ne[1]==0故跳过
for (int i = 2,j=0; i <= n; i++)
{
while (j&&p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j++;
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i++)
{
while (j&&p[j + 1] != s[i]) j = ne[j];
if (p[j + 1] == s[i]) j++;
if (j == n)
{
cout << i - n << " ";
j = ne[j];
}
}
return 0;
}
1)子串指针j都从0开始;
2)永远是子串j+1和主串i比较
3)不满足条件或已找到都要更新j