如果是朴素做法 暴力循环

[字符串暴力循环] [c++]
1
2
3
4
5
6
7
8
9
10
s[N],p[N];
for(int i=1;i<=n;i++)
{
bool flag =true;
for(int j=1;j<=m;j++)
{
if s[i]!=p[i] flag=false;
break
}
}

我们发现匹配慢就是因为回溯的步骤太多了 所以要优化
代码不好理解 但是原理简单
首先得知道最长前缀和最长后缀怎么求
我们发现匹配慢就是因为回溯的步骤太多了

[升级算法] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<bits/stdc++.h>
using namespace std;

const int N=10010,M=10010;

int n,m;
char p[N],s[M];
int ne[N];//定义next[N]概率性报错

int main()
{
cin>>n>>p+1>>m>>s+1; 注意 都是从1开始存的 方便操作
//求ne[N]过程
for(int i=2,j=0;i<=n;i++) //ne[1]=0 第一个元素肯定最长相等前后缀为0
{
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
//kmp匹配过程
for(int i=1,j=0;i<=m;i++)
//从i=1开始从原字符串第一个字符遍历 试图与s[i]匹配的是p[j+1]
{
while(j&&s[i]!=p[j+1]) j=ne[j];
//ne[j]是 字串下标j与j之前的元素 的最长相等前后缀
// j=0则代表重新匹配 只要j不退回起点 且匹配不成功时 j回溯到ne[j] 此时子串j与j之前的元素是和原字符串相同的 继续比较i与j+1
if(s[i]==p[j+1]) j++; 如果下一个相同 继续操作
if(j==n) //如果完全符合
{
cout<<i-n;//输出匹配位置
j=ne[j];
}
}

}

举个例子
下标 1 2 3 4 5 6 7 8
s= a b a b a b c
p= a b a b a b a b
i 1 2 3 4 5 6 7 8
j+1 1 2 3 4 5 6 7 8
ne[]=0 0 1 2 3 4 5 6

首先下标为1均是a 所以i++ j++
这么比较下去 当i=7时 不相等了
此时j=6 ne[6]=4 所以j回溯到4 j+1为5
s= a b a b a b c
p= a b a b a b a b
接着继续相同操作