kmp算法的基本总结

2024-08-28 21:58
文章标签 算法 总结 基本 kmp

本文主要是介绍kmp算法的基本总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

字符串的快速匹配kmp算法
1,朴素的模式匹配算法

目标串      T            t0  t1  t2  t3   t4  t5   t6  t7   t8  t9……
模式串      pat         p0 p1 p2 p3  p4 p5  p6 p7  p8 p9……
如果t0=p0,t1=p1,t2=p2   tm-1=pm-1,则字符串匹配成功,否则将pat串后移一位
形成
     
目标串      T            t0  t1  t2  t3   t4  t5   t6  t7   t8  t9……
模式串      pat              p0 p1 p2 p3  p4 p5  p6 p7  p8 p9……
再次进行匹配判断,失败再后移一位,如果tn-1和pm-1不相等,则匹配结束,返回不存在目标串中不含有字串
 

这种匹配算法是带回溯的算法,一旦比较不相等,就将模式串pat后移一位,从p0开始判断,设目标串的长度为n,匹配串的长度为m,第一趟失败比较m次,第二趟失败又比较m次,依次下去,最坏的情况是比较n-m+1次,在多数的情况下m是远小于n的,所以可以认为算法的时间复杂度是O(m*n)。由此我们引入一种不回溯的匹配算法,提高匹配的效率。



2改进的算法kmp算法

我们给出目标串味T abbaba,模式串为aba
根据朴素算法匹配为

T a b b a b a
P a b a
我们可以看到第一趟t0=p0,t1=p1,t2!=p2;但是p0!=t1;由此可以推断t1=p1!=p0,将P右移一位用t1和p0比较是肯定不相等的,没必要再进行了,p0=p2,所以同样p0!=t2;这一趟也不用比较,我们应该直接将P向右移动3位,直接用t3和p0进行比较,这样匹配就消除了回溯,这就是kmp算法的思想


一般情况 T=“t0t1t2t3t4……tn-1”,模式P="p0p1p2p3pn-1",根据1中的朴素匹配算法可以得到从目标串T的第s个位置ts与模式串的第0个位置进行比较,直到在目标T第s+j位置t(s+j)处失配


这是,可以得到  t(s)t(s+1)t(s+2)t(s+3)……t(s+j-1)=p0p1p2p3……p(j-1)              (x)
那么下一趟应该从目标T中第(s+1)个位置开始匹配
若想成功则有,p0p1p2p3……P(m-1)=t(s+1)t(s+2)t(s+3)………t(s+m);
如果在模式串P中p0p1p2p3……p(j-2)  !=   p1p2p3……p(j-1);                                (y)
则第s+1趟不用比较了
因为由xy式可以得到 p0p1p2p3……p(j-2)  !=t(s+1)t(s+2)t(s+3)……t(s+j-1)

那么第s+2趟呢,
我们要判断一下p0p1p2……p(j-3)与p2p3……P(j-1)的关系。
如果p0p1p2……p(j-3)   !=    p2p3……P(j-1)
仍有
p0p1p2p3……P(j-3)   !=   t(s+2)t(s+3)……t(s+j-1)
这一趟没必要
我们以此类推直到有一个k使p0p1……p(k+1)   !=  p(j-k-2)(j-k-1)……p(j-1)
                                             p0p1……p(k)   =  p(j-k-1)(j0k)……p(j-1)

才有p0p1……p(k)  =  t(s+j-k-1)t(s+j-k)……t(s+j-1)
                                   p(j-k-1)   p(j-k)  ……p(j-1)
这时模式串p已经向后滑动了j-k-1位,因此可以直接从t中的t(s+j)与模式中的p(k+1)开始,继续向下比较。


这个算法中,目标T在第s趟比较失配后,指针s不必回溯,算法下一趟从此开始向下进行比较,而在模式p中,扫描指针p应退回到p(k+1)处
对于不同的j值,k值只依赖与模式p本身的前j个字符的构成。因此我们可以用一个next数组来表示
设模式P=p0p1p2p3……pm-2pm-1,则next数组的取值如下

                       -1(j=0)时
next(j)  =        k+1当0<=k<j-1时,且使的p0p1……p(k)=p(j-k-1)p(j-k)……p(j-1)
                      0其它情况
p=abaabcac

j             0      1        2       3      4      5       6         7     
p            a     b        a        a     b      c       a         c
next(j)    -1    0       0        1      1      2       0         1

下面是用kmp算法实现的匹配代码

<span style="font-size:18px;">int  fastfind(char  *s,char *str,int next[])//s为目标串,str为匹配串
{
int  p=0;
int t=-1;
int lent=strlnen(s);
int lenp=strlen(str);
while(p<lenp&&t<lent)
{
if(p==-1||str[p]==s[t])
{
p++;
t++;
}
else
{
p=next[p];
}
}
if(p<lenp)
return -1;//匹配失败
else
return t=lenp;//匹配成功
}</span>

时间复杂度取决于while循环,因为无回溯,最多比较lent次,时间复杂度为O(lent)。


那么问题来了,我们如何得到next数组。
我们可以用递推的方法得到next数组;设next(j)=k;
则0<=k<j-1且p0p1……pk=p(j-k-1)p(j-k)……p(j-1)
若设next(j+1)=max{k+1|0《=k+1<j},使得p0p1……p(k=1)=p(j-k-1)p(j-k)……p(j)成立
若p(k+1)=p(j),next(j+1)=k+1=next(j)+1;
若p(k+1) != p(j),在p0p1p2……pk中存在p0p1……ph = p(k-h)p(k-h+1)……p(k);
1  存在h值
next(k)=h;
p0p1……ph = p(k-h)p(k-h+1)……p(k) = p(j-h-1)p(j-h)……p(j-1)
如果p(h+1)=p(j)
next(j+1)=h+1=next(k)+1=next(next(j))+1;
否则在p0p1……ph中寻找更小的值,next(h)=t;以此下去,直到next(t)=-1,失败
求next数组代码
void getnext(int next[],char *str)
{
int j=0;
int k=-1;
int lenp=strlen(str);
next[0]=-1;
while(j<lenp)
{
if(k==-1||str[k]==str[j])
{
k++;
j++;
next[j]=k;
}
else
k=netx[k];
}
}

时间复杂度为O(lenp);总的时间复杂度为O(lenp+lent).

参考数据结构书


这篇关于kmp算法的基本总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1116001

相关文章

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

JavaSE正则表达式用法总结大全

《JavaSE正则表达式用法总结大全》正则表达式就是由一些特定的字符组成,代表的是一个规则,:本文主要介绍JavaSE正则表达式用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录常用的正则表达式匹配符正则表China编程达式常用的类Pattern类Matcher类PatternSynta

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

SQL BETWEEN 语句的基本用法详解

《SQLBETWEEN语句的基本用法详解》SQLBETWEEN语句是一个用于在SQL查询中指定查询条件的重要工具,它允许用户指定一个范围,用于筛选符合特定条件的记录,本文将详细介绍BETWEEN语... 目录概述BETWEEN 语句的基本用法BETWEEN 语句的示例示例 1:查询年龄在 20 到 30 岁

mysql中insert into的基本用法和一些示例

《mysql中insertinto的基本用法和一些示例》INSERTINTO用于向MySQL表插入新行,支持单行/多行及部分列插入,下面给大家介绍mysql中insertinto的基本用法和一些示例... 目录基本语法插入单行数据插入多行数据插入部分列的数据插入默认值注意事项在mysql中,INSERT I

mapstruct中的@Mapper注解的基本用法

《mapstruct中的@Mapper注解的基本用法》在MapStruct中,@Mapper注解是核心注解之一,用于标记一个接口或抽象类为MapStruct的映射器(Mapper),本文给大家介绍ma... 目录1. 基本用法2. 常用属性3. 高级用法4. 注意事项5. 总结6. 编译异常处理在MapSt

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

MyBatis ResultMap 的基本用法示例详解

《MyBatisResultMap的基本用法示例详解》在MyBatis中,resultMap用于定义数据库查询结果到Java对象属性的映射关系,本文给大家介绍MyBatisResultMap的基本... 目录MyBATis 中的 resultMap1. resultMap 的基本语法2. 简单的 resul

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa