KMP模板例题回文大师
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP模板例题回文大师相关的知识,希望对你有一定的参考价值。
1️⃣模板
⭐️s
为长度更长的要进行匹配的字符串
⭐️p
为长度小的模式串
ne[i]
:表示模式串中以i
下标为终点的最长公共前后缀的长度
j
:始终是代表能够匹配公共前后缀的结尾位置
注意:ne[1]=0
,所以i
从2开始
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
char s[N], p[N];
int ne[N];
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
cin >> s + 1 >> p + 1;
for(int i = 2, j = 0; i <= m; i++)
while(j && s[i] != s[j + 1]) j = ne[j];
if(p[i] == p[j + 1]) j++;
ne[i] = j;
for(int i = 1, j = 0; i <= n; i++)
while(j && s[i] != p[j + 1]) j = ne[j];
if(s[i] == p[j + 1]) j++;
if(j == m) j = ne[j]; //匹配成功
return 0;
2️⃣例题:回文大师
链接:
https://ac.nowcoder.com/acm/contest/23481/A
其实就是求对于每个
i
, [ 1 , i ] [1,i] [1,i]和 [ j , j + i − 1 ] [j,j+i-1] [j,j+i−1]区间的数构成回文的j
的个数
KMP:
求出数组a
的next
数组,转化为用数组a
对数组从后向前匹配。
也就是对于a
数组进行翻转,反转后的的数组记作b
用a
数组取匹配b
数组,对于每次匹配产生一个j
,表明在j
位置匹配成功一次,所以用f
数组记录结果。
最后因为长度长的片段匹配成功,那么在这个长片段中的短片段也一定会匹配成功 。
把 n e x j nex_j nexj看作 j j j的父亲,则 n e x nex nex数组构成了一颗以 0 0 0为根节点的树(因为 0 ≤ n e x j < j 0\\le nex_j<j 0≤nexj<j),跑完 a a a和 b b b的匹配后再在树上进行子树求和即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int ne[N];
int a[N];
int f[N];
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 2, j = 0; i <= n; i++)
while(j && a[j + 1] != a[i]) j = ne[j];
if(a[j + 1] == a[i]) j++;
ne[i] = j;
for(int i = n, j = 0; i >= 0; i--)
while(j && a[j + 1] != a[i]) j = ne[j];
if(a[j + 1] == a[i]) j++;
f[j] ++;
for(int i = n; i; i--)
f[ne[i]] += f[i];
for(int i = 1; i <= n; i++)
cout << f[i] << " \\n"[i == n];
return 0;
以上是关于KMP模板例题回文大师的主要内容,如果未能解决你的问题,请参考以下文章
算法进阶面试题01——KMP算法详解输出含两次原子串的最短串判断T1是否包含T2子树Manacher算法详解使字符串成为最短回文串