KMP中next数组的理解与应用
理解
1、next数组一直往前走
next数组一直往前走,得到的所有前缀也是当前主串的后缀,当然了,也是当前主串的前缀。
2、周期性字符串
1、周期性字符串$\Leftrightarrow n \,\% \, (n-next[n]) == 0 \ \&\& \ next[n] {\ } {\!}!{=} \ 0 $,循环节长度是$n-next[n]$。

2、next数组往前跳的步长是一样的,除了最后一次。即$i-next[i]$保持恒定。

应用
- 题目一:Period
思路:先求出next数组,然后遍历一遍next数组得到所有字符结尾的字符串循环节的长度及个数
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int maxn = + ;
int nexts[maxn],n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
pre_kmp();
for(int i = ; i <= n; i++)
if (i % (i - nexts[i]) == && nexts[i] != ) printf("%d %d\n", i, i / (i - nexts[i]));
} int main()
{
int T = ;
while (scanf("%d",&n) == && n)
{
scanf("%s", s);
s[n] = '#';
if (T) printf("\n");
printf("Test case #%d\n", ++T);
slove();
}
return ;
}
- 题目二:Power Strings
思路:先求next数组,再直接求循环节
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int maxn = + ;
int nexts[maxn],n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
//int n = strlen(s);
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
pre_kmp();
if (n % (n - nexts[n]) != ) printf("1\n");
else printf("%d\n", n / (n - nexts[n]));
} int main()
{
int T = ;
while (scanf("%s", s) == && s[] != '.')
{
n = strlen(s);
s[n] = '#';
slove();
}
return ;
}
- 题目三:Count The String
思路:求所有前缀出现的次数和,由于next数组回退得到的前缀也是主串的后缀,所以所有next回退的次数加上本身的一次取模就是答案。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int mod = ;
const int maxn = + ;
int nexts[maxn], n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
//int n = strlen(s);
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
int ans = n;
pre_kmp();
for (int i = n; i > ; i--)
{
int k = nexts[i];
while (k > )
{
ans = (ans + ) % mod;
k = nexts[k];
}
}
printf("%d\n", ans);
} int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
scanf("%s", s);
slove();
}
return ;
}
- 题目四:Cyclic Nacklace
思路:题目大意:问至少添加多少个字符,使得这个字符串有至少两个循环节。若本身有两个循环节返回0,否则补充至两个循环节。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int mod = ;
const int maxn = + ;
int nexts[maxn], n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
n = strlen(s);
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
pre_kmp();
int len = n - nexts[n];
if (n % len == && nexts[n] != ) printf("0\n");
else printf("%d\n", len - nexts[n] % len);
} int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%s", s);
slove();
}
return ;
}
参考链接:
1、https://vjudge.net/contest/278481#overview
2、https://blog.csdn.net/hkh746392783/article/details/52015293
KMP中next数组的理解与应用的更多相关文章
- KMP中next数组的理解
next数组是KMP的核心,但对于next数组我们总是有时候感觉明白了,但有时候又感觉没明白,现在我就说下我自己对KMP中next数组的理解,首先next[i]上的数字的意义,next[i]表示的是当 ...
- POJ 2752 KMP中next数组的理解
感觉这里讲的挺好的.http://cavenkaka.iteye.com/blog/1569062 就是不断递归next数组.长度不断减小. 题意:给你一个串,如果这个串存在一个长度为n的前缀串,和长 ...
- POJ 2752 KMP中next数组的应用
题意: 让你从小到大输出给的字符串中既是前缀又是后缀的子串的长度. 思路: 先要了解这个东西: KMP中next数组表示的含义:记录着字符串匹配过程中失配情况下可以向前多跳几个字符,它描述的也是子串的 ...
- KMP算法中next数组的理解与算法的实现(java语言)
KMP 算法我们有写好的函数帮我们计算 Next 数组的值和 Nextval 数组的值,但是如果是考试,那就只能自己来手算这两个数组了,这里分享一下我的计算方法吧. 计算前缀 Next[i] 的值: ...
- poj 2406 Power Strings (kmp 中 next 数组的应用||后缀数组)
http://poj.org/problem?id=2406 Power Strings Time Limit: 3000MS Memory Limit: 65536K Total Submiss ...
- E - Period(KMP中next数组的运用)
一个带有 n 个字符的字符串 s ,要求找出 s 的前缀中具有循环结构的字符子串,也就是要输出具有循环结构的前缀的最后一个数下标与其对应最大循环次数.(次数要求至少为2) For each prefi ...
- 对于kmp求next数组的理解
首先附上代码 1 void GetNext(char* p,int next[]) 2 { 3 int pLen = strlen(p); 4 next[0] = -1; 5 int k = -1; ...
- HDU 3746 Cyclic Nacklace(求补齐循环节最小长度 KMP中next数组的使用 好题!!!)
Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- POJ1961(kmp中Next数组的性质)
对于某个位置i,i - Next[i]是循环节长度,i整除(i - Next[i])时是完整的几个循环元. ; int n, kase, Next[maxn]; char ch[maxn]; inli ...
随机推荐
- YTU 2426: C语言习题 字符串排序
2426: C语言习题 字符串排序 时间限制: 1 Sec 内存限制: 128 MB 提交: 262 解决: 164 题目描述 用指向指针的指针的方法对5个字符串排序并输出.要求将排序单独写成一个 ...
- [NOI 2012] 美食节
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2879 [算法] 首先 , 将每种食物建一个点 , 将每位厨师做的每一道菜建一个点 建 ...
- python 面向对象五 获取对象信息 type isinstance getattr setattr hasattr
一.type()函数 判断基本数据类型可以直接写int,str等: >>> class Animal(object): ... pass ... >>> type( ...
- bzoj3550: [ONTAK2010]Vacation(单纯形法+线性规划)
传送门 直接暴力把线性规划矩阵给打出来然后单纯形求解就行了 简单来说就是每个数记一个\(d_i\)表示选或不选,那么就是最大化\(\sum d_ic_i\),并满足一堆限制条件 然后不要忘记限制每个数 ...
- 洛谷P4374 [USACO18OPEN]Disruption(树链剖分+线段树)
传送门 不难发现,每一条额外修的路径,会对原树上$(u,v)$路径上的所有边产生贡献 于是这就变成了一个路径修改 那么我们把每一条边赋值到它连接的两个点中深度较大的那个上面,然后每一次用树剖+线段树做 ...
- AOP日志框架实现
AOP日志框架实现 JDK动态代理实现日志框架 首先,在项目包com.ay.test 下创建业务接口类BusinessClassService,具体代码如下: BusinessC lassServic ...
- Docker+Jenkins+Git发布SpringBoot应用
Doccker Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之 ...
- 【原创】CentOS 6.5 中安装 Mysql 5.6,并远程连接Mysql
ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.在安装CentOS时,若选择的是Basic Server(可支持J2EE开发),则新安装好的CentOS系统中默认是已经安装了一个mysq ...
- python爬虫爬取腾讯招聘信息 (静态爬虫)
环境: windows7,python3.4 代码:(亲测可正常执行) import requests from bs4 import BeautifulSoup from math import c ...
- Windows API函数大全
WindowsAPI函数大全(精心总结) 目录 1. API之网络函数... 1 2. API之消息函数... 1 3. API之文件处理函数... 2 4. API之打印函数... 5 5. API ...