首页 > 其他分享 >KMP

KMP

时间:2024-07-28 20:29:11浏览次数:11  
标签:int s2 s1 ne KMP 字符串

基础

下文的字符串下标皆从 \(1\) 开始。

考虑定义一个数组 \(ne_i\),指的是设字符串 \(t\) 的前 \(i\) 位为 \(s\)。字符串 \(s\) 的前 \(ne_i\) 位与后 \(ne_i\) 位完全相同,且 \(ne_i\) 取到了最大值,并且 \(ne_i\) 不为字符串 \(s\) 的长度。

是不是觉得很绕?我们举一个例子来更好的说明:

考虑 \(t\) 为 abababc。那么 \(ne\) 数组为 \(0,0,1,2,3,4,0\)。

然后我们考虑如何快速求出 \(ne\) 数组。暴力枚举当然是一种方案,但是复杂度我们不能接受,于是我们考虑优化。

有一个显然的结论,\(ne_{i+1}-ne_i\le 1\),这个就不证明了。

于是我们可以分类讨论,对 \(t_{i+1}\) 是否等于 \(t_{{ne_i}+1}\) 进行分类。

  • 相等,此时 \(ne_{i+1}={ne_i}+1\)。

  • 否则,我们考虑令 \(j=ne_{ne_i}\),判断 \(t_{j+1}\) 是否等于 \(t_{i+1}\) 并重复这一过程。

为什么在否则时我们的做法是正确的,可以看一下图:

然后这样做的时间复杂度是线性的,可以看一下题目。

题目

KMP

板子题,可以直接看一下代码:

#include<bits/stdc++.h>
#define int long long
#define N 1000005
using namespace std;
int ne[N],j,len1,len2;
char s1[N],s2[N];
signed main(){
	cin>>(s1+1)>>(s2+1);
	len1=strlen(s1+1);len2=strlen(s2+1);
	for(int i=2;i<=len2;i++){
		while(j&&s2[i]!=s2[j+1])j=ne[j];
		if(s2[i]==s2[j+1])j++;
		ne[i]=j;
	}
	j=0;
	for(int i=1;i<=len1;i++){
		while(j&&s1[i]!=s2[j+1])j=ne[j];
		if(s1[i]==s2[j+1])j++;
		if(j==len2){
			cout<<i-len2+1<<'\n';
			j=ne[j];
		}
	}
	for(int i=1;i<=len2;i++)cout<<ne[i]<<' ';
	return 0;
}

Compress Words

标签:int,s2,s1,ne,KMP,字符串
From: https://www.cnblogs.com/zxh923aoao/p/18328710

相关文章

  • KMP算法中next数组以及nextval的求解(简单,通俗易懂版)
    以一个题为例:计算上图中next[j]以及nextval[j]的值。【本文中j的下标从1开始。】最长公共前后缀:···前缀:不包含最后一个字符的所有以第一个字符开头的连续子串。···后缀:不包含第一个字符的所有以最后一个字符结尾的连续子串。先看next[j],(1)j的下标......
  • KMP算法(简单易懂版)
    首先举个例子,第一步:此时,B与A的值不匹配。第二步:红色箭头左边的主串与模式串的元素是完全匹配的。第三步:模式串中有“AB”子串是相同的。第四步:直接移动模式串,使前缀移动到后缀的位置。最长公共前后缀:···前缀:不包含最后一个字符的所有以第一个字符开头的连续......
  • kmp & fail树 & border
    kmp经典字符串匹配算法。其实是通过找本身前缀\(i\)的最长border,来实现快速匹配的。这里给出border的定义:字符串\(s\)的一个子串既是它的前缀又是它的后缀,则这个子串是它的border(一般不包含本身)kmp通过fail在border上跳,使得每次前面部分的字符串都是相同的,判断新加入的是否匹......
  • KMP
    做法如何判断一个字符串在另一个字符串里面出现了几次,可以用哈希,不过可能被Hack这里介绍一种总时间\(O(N)\)的写法记\(F(i)\)表示字符串中前缀\([1\)~\(i]\)中最长真前后缀的长度我们可以写出这样一个地推式\(F(i)=\begin{cases}F(i-1)&不是当前字符\\i+1......
  • Z 函数(扩展KMP)
    author:LeoJacob,Marcythm,minghu6约定:字符串下标以\(0\)为起点。定义对于一个长度为\(n\)的字符串\(s\),定义函数\(z[i]\)表示\(s\)和\(s[i,n-1]\)(即以\(s[i]\)开头的后缀)的最长公共前缀(LCP)的长度,则\(z\)被称为\(s\)的Z函数。特别地,\(z[0]=0\)。国外一......
  • 扩展 KMP/exKMP(Z 函数)学习笔记
    声明本文章转载自shangruolin的博客,已经过作者(存疑)同意,帮TA宣传一下。扩展KMP/exKMP(Z函数)学习笔记兼P10479匹配统计题解。LCP:最长公共前缀。Z函数,又称扩展KMP(exKMP),能够在\(O(n)\)的时间内求出一个字符串与其所有后缀的LCP的长度。定义\(z_i\)为字符串\(s\)......
  • KMP+状态转移
    题目:你现在需要设计一个密码S,S需要满足:S的长度是N;S只包含小写英文字母;S不包含子串T;请问共有多少种不同的密码满足要求?由于答案会非常大,请输出答案模1e9+7的余数。输入格式:第一行输入整数N,表示密码的长度。第二行输入字符串T,T中只包含小写字母。输出格式:输出一个......
  • KMP
    CF1326D2Prefix-SuffixPalindrome(Hardversion)给你一个由小写英文字母组成的字符串\(s\)。请找出满足以下条件的最长字符串\(t\):\(t\)的长度不超过\(s\)的长度。\(t\)是一个回文字符串。存在两个字符串\(a\)和\(b\)(可能为空),使得\(t=a+b\)("\(+\)"表......
  • KMP算法
    KMP算法KMP算法是一个字符串算法,通常用于匹配字符串。KMP算法的原理如果我们暴力枚举下标\(i,j\),\(i\)是文本串的下标,\(j\)是模式串(你要在文本串中匹配的字符串)的下标,时间复杂度\(O(NM)\),其中\(N,M\)分别为文本串和模式串的长度。我们看一下匹配过程:(gif动图请耐心观看)......
  • KMP算法
    KMP算法KMP算法是一个字符串算法,通常用于匹配字符串。KMP算法的原理如果我们暴力枚举下标\(i,j\),\(i\)是文本串的下标,\(j\)是模式串(你要在文本串中匹配的字符串)的下标,时间复杂度\(O(NM)\),其中\(N,M\)分别为文本串和模式串的长度。我们看一下匹配过程:(gif动图请耐心观看)......