前言
狗屁不是,建议别看!!!
题目链接
P3375 【模板】KMP 字符串匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
分析
先给个例子
s1:ABCABCABB
s2:ABCABB
若使用朴素算法匹配,当匹配到
s1:ABCAB C ABB
s2:ABCAB B
时,朴素算法会跳出,然后匹配下一位。
最终匹配到
s1:ABC ABCABB
s2: ABCABB
匹配成功
我们发现其中
s1:ABC AB CABB
s2: AB CABB
AB二位在第一次匹配中已经匹配过了
那么如何简化该重复操作呢?
定义next数组(next是关键字,不要用作变量名)
next[i]表示的是s2在i之前的最长的完全相同的前缀后缀长度(不能为整个字符串)
例如:ABCAB
前缀有A、AB、ABC、ABCA
后缀有B、AB、CAB、BCAB
最长的完全相同的前缀后缀为AB,所以next=2
回到第一次匹配中,当匹配到
s1:ABCAB C ABB
s2:ABCAB B
时,即指针i(s1)=6,指针j(s2)=6;
由于next[5]=2,即s2中末尾AB(4,5)与开头AB(1,2)是等价的,并且s2末尾AB与s1中间的AB(4,5)是等价的
所以s1中间的AB可以与s2开头的AB匹配且最长
满足最长即前面的B、C都无法完成匹配
令此时j=next[j-1]+1,再进行下一次匹配
直到j=6(len s2)时匹配结束
那么如何计算next呢?
令i为当前所计算字符串的末尾,j为前缀的末尾
与两个字符串匹配类似
当a[i]!=a[j]时 令j=next[j-1]+1
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=1000006; 5 6 char a[N],b[N]; 7 int ne[N]; 8 9 int main(){ 10 scanf("%s %s", a+1, b+1); 11 int an=strlen(a+1),bn=strlen(b+1); 12 int j=0;//i,j指需要匹配的字符的前一个值 13 for(int i=1;i<bn;i++){ 14 while(j>0&&b[j+1]!=b[i+1]) j=ne[j]; 15 if(b[j+1]==b[i+1]) j++,ne[i+1]=j; 16 } 17 j=0; 18 for(int i=0;i<an;i++){ 19 while(j>0&&b[j+1]!=a[i+1]) j=ne[j]; 20 if(b[j+1]==a[i+1]) j++; 21 if(j==bn){ 22 printf("%d\n", i+1-bn+1); 23 j=ne[j]; 24 } 25 } 26 for(int i=1;i<=bn;i++) cout<<ne[i]<<" "; 27 return 0; 28 }
标签:AB,匹配,int,s2,s1,KMP,next,题解,P3375 From: https://www.cnblogs.com/Idtwtei/p/17591631.html