KMP算法复习笔记

KMP 算法

KMP 算法是一种改进的字符串匹配算法,KMP 算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度 O ( m + n ) O(m+n) O(m+n)

朴素做法

你有两个串 ababbabaaba,求第二个串在第一个串中出现了多少次。

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设两串的长度分别为 n , m n,m n,m,则时间复杂度 O ( n m ) O(nm) O(nm)

我们看到,标 ☆ 的几步可以优化。那应该怎么优化呢?

next 数组

我们发现,当一个串匹配失败时,不总是需要再次从头开始匹配。如果这个串有公共的前后缀,那么可以节约时间。

那我们就在这方面下点功夫。设 n e x t [ x ] next[x] next[x] 表示这个串前 x x x 位的公共的前后缀的最大长度,且 n e x t [ x ] &lt; x next[x]&lt;x next[x]<x x ∈ [ 1 , l e n ] x\in[1,len] x[1,len] l e n len len 表示这个串的长度。

以下为求 n e x t next next 数组的步骤。
定义两个指针 i = 2 , j = 0 i=2,j=0 i=2,j=0
在这里插入图片描述
因为 s t r [ i ] ≠ s t r [ j + 1 ] str[i]\neq str[j+1] str[i]̸=str[j+1],且 j = 0 j=0 j=0,所以 n e x t [ i ] = n e x t [ 2 ] = 0 next[i]=next[2]=0 next[i]=next[2]=0
在这里插入图片描述
因为 s t r [ i ] = s t r [ j + 1 ] str[i]=str[j+1] str[i]=str[j+1],匹配成功。所以将 j j j 指针右移一位, n e x t [ i ] = j + 1 next[i]=j+1 next[i]=j+1
在这里插入图片描述

匹配成功, j j j 右移一位。
在这里插入图片描述

匹配失败,令 j = n e x t [ j ] j=next[j] j=next[j],继续判定。
在这里插入图片描述

仍然无法配对。因此 n e x t [ i ] = 0 next[i]=0 next[i]=0
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

luogu P3375

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register

int next[1000010];
char str1[1000010],str2[1000010];
int len1,len2,t=0;

int main(){
	memset(next,0,sizeof(next));
	scanf("%s%s",str1+1,str2+1);
	len1=strlen(str1+1);len2=strlen(str2+1);
	for(reg int i=2;i<=len2;++i){
		while(t>0&&str2[t+1]!=str2[i]) t=next[t];
		if(str2[t+1]==str2[i]) ++t;
		next[i]=t;
	}
	t=0;
	for(reg int i=1;i<=len1;++i){
		while(t>0&&str2[t+1]!=str1[i])t=next[t];
		if(str2[t+1]==str1[i]) ++t;
		if(t==len2) printf("%d\n",i-t+1);
	}
	for(reg int i=1;i<=len2;++i)
		printf("%d ",next[i]);
}

loj 10043

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register

char str[1010],s[1010];
int next[1010];
int t=0,l,len;
int ans;

int main(){
	do{
		scanf("%s",str+1);
		if(str[1]=='#'&&str[2]=='\0') break;
		scanf("%s",s+1);
		l=strlen(str+1);len=strlen(s+1);
		memset(next,0,sizeof(next));
		t=ans=0;
		for(int i=2;i<=len;++i){
			while(t>0&&s[t+1]!=s[i]) t=next[t];
			if(s[t+1]==s[i]) ++t;
			next[i]=t;
		}
		t=0;
		for(int i=1;i<=l;++i){
			while(t>0&&s[t+1]!=str[i]) t=next[t];
			if(s[t+1]==str[i]) ++t;
			if(t==len) ++ans,t=0;
		}
		printf("%d\n",ans);
	}while(1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
好的,下面是数据结构与算法的复习笔记: 一、数据结构 1. 数组:数组是一种线性数据结构,可以用于存储同一类型的元素。 2. 栈:栈是一种先进后出(Last In First Out)的数据结构,只能在栈顶进行插入和删除操作。 3. 队列:队列是一种先进先出(First In First Out)的数据结构,只能在队尾进行插入操作,在队头进行删除操作。 4. 链表:链表是一种动态数据结构,可以随时插入或删除元素。单向链表只能从头部开始遍历,而双向链表可以从头部或者尾部开始遍历。 5. 树:树是一种非线性数据结构,它由节点和边组成。每个节点有一个父节点和若干个子节点。 6. 堆:堆是一种特殊的树,它分为大根堆和小根堆。大根堆中父节点的值大于等于子节点的值,小根堆中父节点的值小于等于子节点的值。 7. 图:图是由节点和边组成的非线性数据结构,节点之间的连线称为边。图分为有向图和无向图。 二、算法 1. 排序:排序是将一组数据按照某个特定的顺序进行排列的过程。常见的排序算法包括冒泡排序、插入排序、选择排序、快速排序、归并排序等。 2. 查找:查找是在一组数据中找到特定元素的过程。常见的查找算法包括线性查找、二分查找、哈希查找等。 3. 字符串匹配:字符串匹配是在一个文本串中查找一个模式串的过程。常见的字符串匹配算法包括暴力匹配、KMP算法、Boyer-Moore算法、Rabin-Karp算法等。 4. 贪心算法:贪心算法是一种在每一步选择中都采取当前状态下最优解的策略。贪心算法常用于求解最小生成树、最短路径等问题。 5. 动态规划:动态规划是一种通过划分问题为子问题并解决子问题来求解原问题的方法。动态规划常用于求解最长公共子序列、背包问题等。 以上是数据结构和算法的复习笔记,希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值