学习笔记——KMP

字符匹配算法一直是所有人的噩梦。除却难懂的思路,难卡的算法复杂度也是一个问题

下面是少许常见字符匹配算法及其常见衍生算法

也许有点看不清楚,但大致可以看到KMP算法的衍生算法是最多的

大致优缺点

KMP:速度平均O(n+m),最慢O(nm)
BM&Sunday(未写):速度平均O(n),最慢O(nm)
哈希(未写):平均复杂度O(n),但有冲突风险,基本万能

(仅罗列单字符串比较)

其中BM&Sunday都是KMP的优化,所以优先讲KMP

什么是KMP

KMP是一种单字符串比较问题

举个例子:

有文本串 S S S S S C SSSSSC SSSSSC和模式串 S S C SSC SSC

现在要在文本串中找出模式串,请问怎么办?

肉眼都可以知道SSC在哪里,但如果文本串太长,就不方便了

因此,暴力法应运而生,以效率低下但十分稳定而著称

方法:对于每个文本串中的字母作为开头,匹配模式串

代码:

cpp 复制代码
const int N=1007;//基本是最大值
int find(int s[],int t[],int n,int m){
	for(int i=0;i+m-1<n;i++){
		bool flg=1;
		for(int j=0,k=i;j<m;j++,k++)
			if(s[k]!=t[j])
				flg=0;
		if(flg)
			return i;
	}
	return -1;
}

有一种简洁而不失优雅的暴力美

怎么优化?

不难发现暴力法每一步都没有利用好上次的量,但怎么利用呢?

很容易发现,我们希望每次 j j j回退的距离尽量小

首先,我们希望能够最好是对于以一个节点为结尾(开头也可以,但结尾方便),迅速找到其对应的最远的长度。(说白了就是找出最大的 l e n len len,满足文本串 [ i − l e n + 1 , i ] [i-len+1,i] [i−len+1,i]等于模式串 [ 1 , l e n ] [1,len] [1,len])

我们考虑上一次计算对这次的贡献,已知对于文本串中第 i − 1 i-1 i−1个的值为 a i − 1 a_{i-1} ai−1,上一次计算结果为 x x x,此时可以发现,这次结果最大为 x + 1 x+1 x+1,并且对于这次结果 y y y,存在模式串 b b b中 b y − 1 = b x = a i − 1 b_{y-1}=b_{x}=a_{i-1} by−1=bx=ai−1(显然的),并且有 b y = a i b_y=a_i by=ai以及 b [ 1 , y − 1 ] = b [ x − y + 2 , x ] b[1,y-1]=b[x-y+2,x] b[1,y−1]=b[x−y+2,x]

也就是说,只要统计对于一个 x x x,找出 b b b的 [ 1 , x ] [1,x] [1,x]区间段的公共前后缀(以下称为border)就行了(公共前后缀,就是一对相同长度的前缀和后缀,满足前缀=后缀)

不难发现,border的border是border,如图

(有点丑,见谅)

这意味着,我们可以通过最长border求出所有border,我们命名最长border数组为nx数组

求nx数组跟匹配思路类似,不再赘述,何况也有许多讲的比我好的,我只是提供一种在模式串上求border的方法罢了

代码:

cpp 复制代码
const int N=1e6+7;
int nx[N];
int kmp(char s[],char t[],int n,int m){
	if(m>n)return -1;
	for(int i=1,j=0;i<m;i++){
		while(j&&t[i]!=t[j])j=nx[j-1];
		nx[i]=(t[i]==t[j]?++j:0);
	}
	for(int i=0,j=0;i<n;i++){
		while(j&&s[i]!=t[j])j=nx[j-1];
		if(s[i]==t[j])
			if(++j==m)
				return i;
	}
	return -1;
}
相关推荐
大丈夫立于天地间14 分钟前
ISIS基础知识
网络·网络协议·学习·智能路由器·信息与通信
doubt。22 分钟前
【BUUCTF】[RCTF2015]EasySQL1
网络·数据库·笔记·mysql·安全·web安全
Chambor_mak1 小时前
stm32单片机个人学习笔记14(USART串口数据包)
stm32·单片机·学习
Zelotz1 小时前
线段树与矩阵
笔记
汇能感知2 小时前
光谱相机在智能冰箱的应用原理与优势
经验分享·笔记·科技
PaLu-LI2 小时前
ORB-SLAM2源码学习:Initializer.cc⑧: Initializer::CheckRT检验三角化结果
c++·人工智能·opencv·学习·ubuntu·计算机视觉
yuanbenshidiaos2 小时前
【大数据】机器学习----------计算机学习理论
大数据·学习·机器学习
汤姆和佩琦2 小时前
2025-1-20-sklearn学习(42) 使用scikit-learn计算 钿车罗帕,相逢处,自有暗尘随马。
人工智能·python·学习·机器学习·scikit-learn·sklearn
Tech智汇站2 小时前
Quick Startup,快捷处理自启程序的工具,加快电脑开机速度!
经验分享·科技·学习·学习方法·改行学it
qq_312738452 小时前
jvm学习总结
jvm·学习