KMP模式匹配 学习笔记
功能
能在线性时间内判断字符串\(A[1~N]\)是否为字符串\(B[1~M]\)的子串,并求出字符串\(A\)在字符串\(B\)中各次出现的位置。
实现
1.对字符串\(A\)进行自我“匹配”,求出一个数组\(next\),其中\(next[i]\)表示“\(A\)中以\(i\)结尾的非前缀子串”与“\(A\)的前缀”能够匹配的最长长度。特别地,当不存在这样的\(j\)时,令\(next[i]=0\).由于\(next\)的对象是非前缀子串,所以\(next[1]=0\);
概念解释:字符串的前缀是指字符串的任意首部。比如字符串“\(abbc\)”的前缀有“\(a\)”,“\(ab\)”,“\(abb\)”,“\(abbc\)”。同样,字符串的任意尾部是字符串的后缀,“\(abbc\)”的后缀有“\(c\)”,“\(bc\)”,“\(bbc\)”,“\(abbc\)”。

\(next[i]=max{j},其中j<i并且A[i-j+1~i]=A[1~j]\)
2.对字符串\(A\)与\(B\)进行匹配,求出一个数组\(f\),其中\(f[i]\)表示“\(B\)中以\(i\)结尾的子串”与“\(A\)的前缀”能够匹配的最长长度。

\(f[i]=max{j},其中j<=i并且B[i-j+1~i]=A[1~j]\)
代码
KMP算法\(next\)数组的求法
1.初始化\(next[1]=j=0\),假设\(next[1~i-1]\)已求出,下面求解\(next[i]\).
2.不断尝试扩展匹配长度\(j\),如果扩展失败(下一个字符不相等),令\(j\)变为\(next[j]\),直至\(j\)为\(0\)(应该从头开始匹配)。
3.如果能够扩展成功,匹配长度\(j\)就增加\(1\).\(next[i]\)的值就是\(j\).
next[1]=0;
for(int i=2,j=0;i<=n;i++)
{
	while(j>0&&&a[i]!=a[j+1]) j=next[j];
	if(a[i]==a[j+1]) j++;
	next[i]=j;
}
KMP算法\(f\)数组的求法
for(int i=1,j=0;i<=m;i++)
{
	while(j>0&&(j==n||b[i]!=a[j+1])) j=next[j];
	if(b[i]==a[j+1]) j++;
	f[i]=j;
	//if(f[i]==n),此时就是A在B中的某一次出现
}
例题
例题1:P3375 【模板】KMP字符串匹配
这道题完完全全就是对上述两个代码块的直接使用。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000010
#define M 1000010
char p[N],s[M];//p模式串 s主串
int nex[N],f[N];
int ans;
using namespace std;
int main()
{
	cin>>s+1>>p+1;
	int lp=strlen(p+1);
	int ls=strlen(s+1);
	for(int i=2,j=0;i<=lp;i++)
	{
		while(j>0&&p[i]!=p[j+1]) j=nex[j];
		if(p[i]==p[j+1]) j++;
		nex[i]=j;
	}
	for(int i=1,j=0;i<=ls;i++)
	{
		while(j&&(j==lp||s[i]!=p[j+1])) j=nex[j];
		if(s[i]==p[j+1]) j++;
		f[i]=j;
		if(f[i]==lp)
		{
			ans=i-lp+1;
			printf("%d\n",ans);
		}
	}
	for(int i=1;i<=lp;i++) printf("%d ",nex[i]);
	return 0;
}
例题2




这道题引入了一个新概念:循环同构。
其实,判断两个串是否循环同构也可以利用上述的KMP算法。比如欲判断字符串\(A\)和\(B\)是否循环同构,我们只需要新定义一个字符串\(C\)为重复两遍的\(A\),就是说,若\(A=aab\),则\(C=aabaab\).然后用KMP判断\(C\)中是否有\(B\),若有,则\(A\)和\(B\)循环同构,反之则不循环同构。
具体到这道题,我们可以枚举所有因数,然后按因数分段,再用上述方法判断。一旦出现两段之间非循环同构就break,这样能节省不少时间。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5e6+10;
int t,n;
char a[N];
int nex[N],b[N],f[N];
void kmp(int x)
{
	nex[1]=0;
	for(int i=2,j=0;i<=x;i++)
	{
		while(j>0&&a[i]!=a[j+1]) j=nex[j];
		if(a[i]==a[j+1]) j++;
		nex[i]=j;
	}
}
bool judge()
{
	for(int i=2;i<n;i++)
	{
		if(n%i==0)
		{
			int x=i,p=1,w=n/x;
			bool kx=1;
			kmp(x);
			for(int j=1;j<=w-1;j++)
			{
				for(int k=x*j+1;k<=x*(j+1);k++)
					b[k-x*j]=b[k+x-x*j]=a[k];
				for(int k=1,w=0;k<=x*2;k++)
				{
					while(w>0&&(w==x||b[k]!=a[w+1])) w=nex[w];
					if(b[k]==a[w+1]) w++;
					f[k]=w;
					if(f[k]==x)
					{
						kx=1;
						p++;
						break;
					}
					kx=0;
				}
				if(!kx) break;
			}
			if(p==w) return 1;
		}
	}
	for(int j=1;j<n;j++)
		if(a[j]!=a[j+1])
			return 0;
	return 1;
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%s",&n,a+1);
		if(n==1)
		{
			puts("No");
			continue;
		}
		if(judge()) puts("Yes");
		else puts("No");
	}
	return 0;
}
KMP模式匹配 学习笔记的更多相关文章
- KMP字符串模式匹配学习笔记
		KMP算法实验 1.编程计算模式串(子串)的next值.2.利用KMP算法在主串中找到模式串的位置. 参考代码:---------int getNexlVal( char * s, int j)// ... 
- [KMP]【学习笔记】
		Oulipo Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 36916 Accepted: 14904 Descript ... 
- HDU 4333 Revolving Digits [扩展KMP]【学习笔记】
		题意:给一个数字,每一次把它的最后一位拿到最前面,一直那样下去,分别求形成的数字小于,等于和大于原来数的个数. SAM乱搞失败 当然要先变SS了 然后考虑每个后缀前长为n个字符,把它跟S比较就行了 如 ... 
- 串的应用与kmp算法讲解--学习笔记
		串的应用与kmp算法讲解 1. 写作目的 平时学习总结的学习笔记,方便自己理解加深印象.同时希望可以帮到正在学习这方面知识的同学,可以相互学习.新手上路请多关照,如果问题还请不吝赐教. 2. 串的逻辑 ... 
- 「学习笔记」字符串基础:Hash,KMP与Trie
		「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ... 
- 【学习笔记】oracle 比较运算符,逻辑运算符,特殊运算符,判断空值,大小写敏感
		比较运算符:> 大于,< 小于 >= 大于等于,<= 小于等于 = 等于,!=,<>,^= 不等于 逻辑运算符运算的优先顺序:NOT > AND > O ... 
- 两千行PHP学习笔记
		亲们,如约而至的PHP笔记来啦~绝对干货! 以下为我以前学PHP时做的笔记,时不时的也会添加一些基础知识点进去,有时还翻出来查查. MySQL笔记:一千行MySQL学习笔记http://www.cnb ... 
- awk 学习笔记
		awk的语法有两种形式 awk [options] 'script' var=value file(s) awk [options] -f scriptfile var=value file(s) 选 ... 
- PHP学习笔记 - 进阶篇(5)
		PHP学习笔记 - 进阶篇(5) 正则表达式 什么叫正则表达式 正则表达式是对字符串进行操作的一种逻辑公式,就是用一些特定的字符组合成一个规则字符串,称之为正则匹配模式. $p = '/apple/' ... 
随机推荐
- linux安全之网络设置
			可以通过/etc/sysctl.conf控制和配置Linux内核及网络设置. # 避免放大攻击 net.ipv4.icmp_echo_ignore_broadcasts = 1 # 开启恶意icmp错 ... 
- git diff与linux diff的输出格式之unified format
			前言 前面有一篇文章<一个有些意思的项目--文件夹对比工具(一)>,里面简单讲了下diff算法之--Myers算法. 既然是算法,就会有实现,比如git diff中有Myers的实现,gi ... 
- 浏览器窗口尺寸相关的 API 整理图
			整理浏览器中和屏幕尺寸相关的 API: 其中和文档相关的属性,例如 innerWidth.innerHeight.event.x.event.y 的单位为 CSS 像素,如果页面存在缩放,则需乘上缩放 ... 
- js中数组去重的方法
			在实际工作或面试中,我们经常会遇到"数组去重"问题,接下来就是使用js实现的数组去重的多种方法: 1.借助ES6提供的Set结构 var arr = [1,1,2,2,3,3,4, ... 
- gorm tips
			约定的列名 type User struct { ID uint // 列名是 `id` Name string // 列名是 `name` Birthday time.Time // 列名是 `bi ... 
- 基于 Sequelize.js + Express.js 开发一套 Web 后端服务器
			什么是 Sequelize 我们知道 Web 应用开发中的 Web 后端开发一般都是 Java.Python.ASP.NET 等语言.十年前,Node.js 的出现使得原本仅限于运行在浏览器中的 Ja ... 
- 上传代码到GitHub仓库
			上传代码到GitHub仓库 准备工作 意思是自从 21 年 8 月 13 后不再支持用户名密码的方式验证了,需要创建个人访问令牌(personal access token). 这里就不多说了 Git ... 
- CF1450G. Communism(状压DP)
			题面 有一个字符串 s \tt s s 和一个有理数 k \tt k k,可以进行如下操作任意次: 选一个当前串中存在的字符 x \tt x x ,令 i 1 , i 2 , . . . , i m ... 
- CSP-S 2020 T4 贪吃蛇 (双队列模拟)
			题面 题解 先看数据,T<=10,用平衡树或优先队列是可以拿70分的,大体思路和正解思路是一样的,每次直接修改,然后模拟. 我们模拟的时候,主要是在过程中算出最终被吃的有选择权的蛇的最后选择时刻 ... 
- 美团组件化事件总线方案改进:ModularEventBus
			请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ... 
