前置概念:
- 字符串匹配:查找一个字符串在另一个字符串中有多少个,并得到它们的位置
- 模式串:用于匹配的字符串(例如在abcabc中查找abc,则abc是模式串)
- 匹配主串:用于被匹配的字符串(例如在abcabc中查找abc,则abcabc是匹配主串)
- KMP算法:单模式串的字符串匹配算法
- AC自动机*:多模式串的字符串匹配算法(基于trie树和kmp算法的思想)
算法思想:
- 充分利用模式串内部的信息以减少时间复杂度,也就是通过预处理模式串减少字符串匹配时的匹配次数
算法过程:
- 进行模式串的预处理,也就是计算next数组
- 进行字符串匹配,也就是进行KMP算法的主过程
模板地址:https://www.luogu.org/problemnew/show/P3375
个人思路:
- KMP()与get_next()方法一个是对匹配串进行匹配,另一个是计算模式串的next数组.
- 两个方法都有两个局部变量index和nowvalue,分别指示当前匹配位置和当前next值。所不同的是,KMP()方法中由于不需要对next数组进行初始化,nowvalue只需初始化为0,而get_next()方法中由于需要增加不可匹配的特殊判断值,所以next[0]和nowvalue都要初始化为-1
- KMP()方法中nowvalue==len2指匹配长度达到要求。这时候输出一个答案为当前位置即可.
- KMP()方法中如果当前字符匹配成功则直接将index和nowvalue后移一位即可,而在模式字符串自我匹配中只需要对下一位的next数组进行初始化,也就是next[++index]=++nowvalue.
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int SIZE=1000001;
int n,k,len1,len2;
int next[SIZE];
char s1[SIZE],s2[SIZE];
void get_next(){
int index=0,nowvalue;//位置和当前位的next值
next[0]=nowvalue=-1;//设置第一位为无法向前跳转
while(index<len2){
if(nowvalue==-1||s2[index]==s2[nowvalue])next[++index]=++nowvalue;
//如果当前next值为-1或匹配成功,则下一位的next值增加
else nowvalue=next[nowvalue];//如果匹配失败,则next值 向前跳转
}
}
void KMP(){
int index=0,nowvalue=0;
while(index<len1){
if(nowvalue==-1||s1[index]==s2[nowvalue])
index++,nowvalue++;
else nowvalue=next[nowvalue];
if(nowvalue==len2)printf("%d\n",index-len2+1);
}
}
int main(){
scanf("%s",s1);
scanf("%s",s2);
len1=strlen(s1),len2=strlen(s2);
get_next();
KMP();
for(int i=1;i<=len2;i++)
printf("%d ",next[i]);
return 0;
}