0%

P3375 【模板】KMP(前缀函数)

思路讲解

https://cp-algorithms.com/string/prefix-function.html

【KMP 学一遍忘一遍?ACM 金牌选手用可视化直击本质,理解了内核后想忘记都难!】 【精准空降到 04:05】 https://www.bilibili.com/video/BV1Er421K7kF/?share_source=copy_web&vd_source=6ca0bc05e7d6f39b07c1afd464edae37&t=245

那么我们容易发现,这个

image

ABC……ABC+D,那么如果前缀字符串后面跟着D,那么就是pi函数=4,但是如果后面不是D,那要怎么办?

不难发现,S[i+1]=S[π[i]+1]π[i+1]=π[i]+1S[i+1]=S[\pi[i]+1] \Rightarrow\pi[i+1]=\pi[i]+1(注意,这里我采用的是1-based,这更自然)。这不言而喻。(上面的这个图片已经解释了,我们再细化一下)

image

当然,这个是皆大欢喜的情况,但是如果出现失配了怎么办?

image

这个 pi_next(),为什么一定是这个 pi_next()。可以使用反证法

image

okay,问题就来到了,怎么样使用前缀数组实现这个文本串和模式串的这个匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//                  文本串             模式串
vector<ll> kmp(const string &s1,const string &s2){ // 返回总前缀数组pi
string S;
S='#'+s2+'#'+s1; // 采用1-based
N=SZ(S)-1;
vector<ll> pi(N+1,0);
FOR(i,1,N){
if(i==1) continue;
ll len=pi[i-1];
// if(S[i]==S[len+1]){
// pi[i]=len+1;
// }
while(true){
if(S[i]==S[len+1]){
pi[i]=len+1;
break;
}
if(len==0) break;
len=pi[len];
}
}
return pi;
}

特别的,我们认为 i=1 的时候 pi[i]=0。

他采用了 0-based,意思和我一样。

image

AC代码

心路历程(WA,TLE,MLE……)