KMP算法

【KMP算法详解——适合初学KMP算法的朋友】 KMP算法的初级体验,只为抛砖引玉之用 阅读详情

1.原始的字符串匹配方法

算法基本思想:从主串S的第pos个字符起和模式的第一个字符比较之,若相等,则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式的字符比较之。依次类推,直至模式T中的每个字符依次和主串S中的一个连续的字符序列相等,则称匹配成功,否则称匹配不成功。

这种匹配方法理解起来很简单,中心思想就是逐个比较字符,每当一趟匹配过程中出现字符不等时,主串的比较指针i需要回溯。时间复杂度为O(n*m)。n为主串的长度,m为匹配的子串的长度。

2.KMP算法

该算法相比原始的字符串匹配方法,其效率更高,省去了一些冗余的、重复的匹配步骤。

算法基本思想:在进行主串和子串匹配过程中,每当一趟匹配过程中出现字符比较不等时,不需要回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离,继续进行比较。

该算法的关键在于当每次匹配不等时,如何确定子串向右“滑动”的距离。其实该“滑动”距离与主串的结构无关,其取决子串的结构中是否存在有重复的部分。假设主串为s1s2…sn,模式串为p1p2…pn,当主串中第i个字符和模式中第j个字符匹配失败时,主串中第i个字符(i指针不回溯)应与模式中哪个字符再比较?

假设此时应与模式中第k(k<j)个字符继续比较,则模式中前k-1个字符的子串必须满足下列关系式,且不可能存在k’>k也满足下列关系式

                                                               “p1p2…pk-1”=“si-k+1si-k+2…si-1”

而已经得到的“部分匹配”的结果是

                                                              “pj-k+1pj-k+2…pj-1”=“si-k+1si-k+2…si-1”

联合以上两式得

                                                             “p1p2…pk-1”= “pj-k+1pj-k+2…pj-1”

上述公式表明,若模式串中存在前k-1个字符和模式串中后k-1个字符相等(前缀和后缀相同),那么当下次匹配时,只需将模式串中第k个字符与主串中的第i个字符比较即可(即下次匹配时j=k),而不用将j回溯到模式串的首字符。由此可导出next[j]=k函数,表明当模式中第j个字符与主串中第i个字符匹配失败时,在模式串中需重新和主串第i个字符进行比较的字符的位置。

                                            

获取模式串各字符的next函数值的代码如下:

void getnext(char s[],int next[])
{
	int i=1,j=0;    
	next[1]=0;    //初始化next函数 
	while (i<s[0])   //s[0]为串的长度 
	{
		if (j==0||s[j]==s[i])   //s[j]为前缀单个字符,s[i]为后缀单个字符,当两者相等时,即前缀和后缀匹配成功,next[i+1]=next[i]+1。
		{                     //或者当j=0时,说明指针j回溯到头仍然无法找到匹配的前缀和后缀,此时next[i+1]=0+1=1; 
			j++;
			i++;
			next[i]=j;
		}
		else
		{
			j=next[j];     //前缀和后缀不等,指针j向前回溯 
		}
	} 
} 

完整KMP算法代码如下:

#include <stdio.h>
#include <string.h>
//KMP算法
int next[1000]; 
void getnext(char s[],int *next)
{
	int i=1,j=0;    
	next[1]=0;    //初始化next函数 
	while (i<s[0])   //s[0]为串的长度 
	{
		if (j==0||s[j]==s[i])   //s[j]为前缀单个字符,s[i]为后缀单个字符,当两者相等时,即前缀和后缀匹配成功,next[i+1]=next[i]+1。
		{                     //或者当j=0时,说明指针j回溯到头仍然无法找到匹配的前缀和后缀,此时next[i+1]=0+1=1; 
			j++;
			i++;
			next[i]=j;
		}
		else
		{
			j=next[j];     //前缀和后缀不等,指针j向前回溯 
		}
	} 
} 

int Index(char S[],char s[],int pos)
{
	int i=pos,j=1;
	if (i<1 ||i>S[0]) return 0;
	getnext(s,next);          //获取子串各字符的next函数值 
	while(i<=S[0] && j<=s[0])  
	{
		if (j==0||S[i]==s[j]) //如果对应字符相等则指针同时下移,当模式串的指针j回溯到头,在模式串中找不到与主串第i个字符对应的字符时 
		{                    // 则两指针同时下移 
			i++;
			j++;
		}
		else                 // 匹配字符不等,回溯j指针 
		{
			j=next[j];
		}
	}
	if (j>s[0])         //j大于子串长度,则匹配成功,返回首字符位置 
	{
		return i-s[0];
	}else              //匹配失败,返回0 
	{
		return 0;
	}
	
}

int main()
{
	char S[1000],s[1000];
	int pos;
	printf("输入主串\n");
	scanf("%s",S+1);
	*S=strlen(S+1);
	printf("输入要查找的串\n");
	scanf("%s",s+1);
	*s=strlen(s+1);
	printf("输入查找的起始位置\n"); 
	scanf("%d",&pos);
	printf("在主串中的位置为%d\n",Index(S,s,pos)); 
	return 0;
}

3.改良的KMP算法

在匹配过程中,KMP算法还是有缺陷的。缺陷在于匹配不符情况下,j指针向前回溯的步骤可能会产生冗余。列如当主串S=“aaaabcde”,模式串s=“aaaaax”时,此时模式串的各字符的next函数值为012345。当匹配到主串第五个字符(i=5),模式串第5个字符(j=5)时,‘b’不等于‘a’,此时j指针就应该回溯。按照next数组,指针j回溯到4,即主串第5个字符与模式串的第4个字符比较,然后不等,指针j又回溯到3,继续比较,一直到指针j回溯到1,发现不等后,i指针才加1。在此过程中,模式串中第1,2,3,4个字符都与第5个字符字符‘a’相等,因此主串第5个字符和模式串中第1,2,3,4进行比较的步骤是多余的。为了改良这个缺陷,我们将首字符的next函数值去取代和它相等字符后续的next函数值,这样模式串各字符新的next函数值分别为000005,就避免了冗余步骤的产生。

获取改良的nextval数组如下:

void getnextval(char s[],int *nextval)
{
	int i=1,j=0;    
	nextval[1]=0;    //初始化nextval函数 
	while (i<s[0])   //s[0]为串的长度 
	{
		if (j==0||s[j]==s[i])   
		{                    
			j++;
			i++;
			if (s[i]!=s[j])   //若当前字符和要回溯的字符不等,则正常记录j值 
			{
				nextval[i]=j;
			}else            //若相等,则当前字符的nextval值等于要回溯字符的nextval值 
			{
				nextval[i]=nextval[j];
			}
		}
		else
		{
			j=nextval[j];     //前缀和后缀不等,指针j向前回溯 
		}
	} 
} 

4.总结

相比原始的字符串匹配算法,KMP算法时间复杂度仅为O(n+m),其算法效率得到了大幅度的提高。但是该算法的优异性也只是体现在当主串和模式串之间存在许多部分匹配的情况下,否则该算法和原始的字符串匹配算法差异并不明显。





                                                               


KMP算法~~完整的 KMP算法~很好的资料 听不容易弄来的~ 分享给大家 立即下载

相关推荐

群晖NAS变身私有Git服务器:DS218+部署与TortoiseGit客户端实战指南

本文详细介绍了如何将群晖NAS(如DS218+)变身为私有Git服务器,并配置TortoiseGit客户端实现高效代码管理。通过硬件检查、系统更新、Git Server套件安装及权限配置等步骤,帮助开发者在局域网内搭建安全、高速的代码托管环境,特别适合小团队协作。

weixin_29252171的博客 223

KMP模版(输出多个匹配)

#include&lt;stdio.h&gt; #include&lt;string.h&gt; const int INF =1000005; /* 3 BAPC BAPC AZA AZAZAZA VERDI AVERDXIVYERDIAN Sample Output 1 3 0 */ int n,m; char str[INF] ; //主串 char p[INF]; //模式串 i...

唐宋元明清的博客 983

【逆强化学习-1】学徒学习(Apprenticeship Learning)

逆强化学习算法1:学徒学习。算法原理+算法步骤+代码+仿真:一个基于gym的小车上山的仿真。附赠学徒学习+Q-Table及学徒学习+DQN的全套代码。

体会编程语言独到的美 7494

PAT考试大纲/如何刷pat(想要在pat甲级拿80到90分)

乙级(Basic Level) 考生应具备以下基本能力: 1· 基本的C/C++的代码设计能力,以及相关开发环境的基本调试技巧; 2· 理解并掌握最基本的数据存储结构,即:数组、链表; 3· 理解并熟练编程实现与基本数据结构相关的基础算法,包括递归、排序、查找等; 4· 能够分析算法的时间复杂度、空间复杂度和算法稳定性; 5· 具备问题抽象和建模的初步能力,并能够用所学方法解决实际问题。 甲级(A...

a656418zz的博客 2万+

VSCode多文件C语言项目编译实战:从配置到运行

本文详细讲解了如何在VSCode中配置多文件C语言项目的编译环境。通过手把手教学,指导读者创建项目结构、编写代码,并重点深度配置task.json与launch.json文件,实现一键编译和调试所有C文件,解决常见的“undefined reference”等链接错误,提升开发效率。

g8f9d0s1a2的博客 1098

摄像头模组选型避坑指南:如何根据Sensor和Lens参数匹配最佳组合

本文深入解析摄像头模组选型中Sensor与Lens的核心参数匹配要点。重点阐述了主光线角(CRA)匹配对边缘画质的关键影响,并提供了传感器尺寸、像素尺寸、焦距、光圈等参数的协同选型策略与实战避坑指南,帮助工程师在手机、安防、车载等不同应用场景下实现性能与成本的最佳平衡。

ee345的博客 618

KMP算法真的搞死人,终于搞懂了

现总结如下:想理解KMP算法就要先看看最原始的模式匹配int match(char *string, char *pat)  //原模式匹配函数...{    int i = 0, j = 0;    while (i  strlen(string) && j  strlen(pat)) ...{        if (sting[i] == pat[j]) ...{           

博客已转到w3er.com 2348

UNITE真菌数据库使用避坑指南:从下载到注释的完整流程

本文提供了UNITE真菌数据库从下载到注释的完整实战指南。针对真菌ITS序列分析,重点解析了数据库版本选择、格式转换的常见陷阱,并详细介绍了如何训练优化的sklearn分类器以提升物种注释的精度和可靠性,帮助用户构建高效稳定的本地工作流。

weixin_29240343的博客 199

PAT---字符串处理题总结

sscanf与sprintf是处理字符串问题的利器, sscanf从单词上可以理解为string+scanf,(从左往右) sprintf则可以理解为string+printf,均在stdio.h头文件下。(从右往左) sscanf(s,"%lf",&num); sprintf(s1,"%.2f",num); 写题常用的: to_string():int 转string stoi():string转换为int,s[i]是char,不符合参数要求,可以用s.substr(i,1)返回子串

chstor's blog 305

2024年上半年网络工程师下午真题及答案解析

位于MPLS域边缘、连接其他网络的LSR称为( 3 ),区域内部的LSR称为核心LSR(CoreLSR)IP报文进入MPLS网络时,MPLS入口设备分析IP报文的内容并为其添加合适的标签,所有MPLS网络中的LSR根据标签转发数据,当该IP报文离开MPLS网络时,标签由出口LER弹出。LSP的出口LER称为( 6 )。某高校网络拓扑如下图所示,两校区核心(CORE-1、CORE-2),出口防火墙(NGFW-1、NGFW-2)通过校区间光缆互联,配置OSPF实现全校路由收敛,两校区相距40km。

bsefef的博客 2474

基于JAVA的GB28181实现之SIP服务核心组件解析

本文深入解析了基于JAVA的GB28181标准中SIP服务的核心组件实现,包括协议栈选择、消息处理引擎、事务管理器等关键技术点。通过实战案例分享海康威视、大华设备的特殊处理技巧,并提供性能优化和常见问题排查指南,帮助开发者高效构建稳定的视频监控系统。

weixin_30892037的博客 264

PTA KMP 串的模式匹配 (25 分)

#include &lt;bits/stdc++.h&gt; using namespace std; typedef int Pos; #define NotFound -1 void BuildMatch(char *pattern, int *match); Pos KMP(char *str, char *pattern); int main() { #ifdef ONLINE_JU...

Cathy1122334455的博客 3436

MATLAB 基于深度学习的步态识别算法仿真

步态识别是一种通过分析人体行走方式来识别身份的技术。基于深度学习的步态识别算法利用卷积神经网络 (CNN) 提取步态特征,并通过分类器进行身份识别。基于深度学习的步态识别算法是实现身份识别的重要手段,具有广泛的应用前景。MATLAB 提供了丰富的工具和函数,可以方便地进行算法仿真和性能评估。

走向CTO的路上... 518

KMP算法详解

KMP算法是一种字符串模式匹配算法,不同的来源讲解方式也不一样,很容易混乱,在这里以一种特殊的方式来讲解KMP算法,希望大家不再被这个问题所困扰。 一. 一些基础问题 什么是字符串的模式匹配? 给定两个串S=“s1s2s3 …sn”和T=“t1t2t3 …tn”,在主串S中寻找子串T的过程叫做模式匹配,T称为模式。 如何寻找? 我们先从比较好理解的暴力匹配(朴素模式匹配BF算法)开始,进而引出K...

yyzsir的博客 9万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

图解算法:KMP算法

目录第一章 暴力匹配实现第二章 KMP算法介绍第三章 KMP算法原理第四章 KMP的匹配表第五章 KMP算法实现 项目地址:https://gitee.com/caochenlei/algorithms 第一章 暴力匹配实现 【问题描述】 有一个字符串 str1 = “BBC ABCDAB ABCDABCDABDE”,和一个子串 str2 = “ABCDABD”,现在要判断 str1 是否含有 str2,如果存在,就返回第一次出现的位置,如果不存在,就返回-1。 【问题思路】 【代码实现】 publ

轻松的小希 8311

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

kmp算法总结

搞ACM也有三年了,期间学习了不少算法,到12月把上海站打完也要成退役狗了。最近突然想把学过的一些算法回过头来好好总结一下,于是就有了我的算法总结系列。这是这个系列的开端,所以先写一个简单点的算法,以后会慢慢复习一些复杂的算法,最后还是希望自己能够坚持下去吧。 KMP算法 KMP算法是一种线性时间复杂度的字符串匹配算法,它是对BF(Brute-Force,最基本的字符串匹配算法)的改进。对

ddyyxx的程序员之路 1万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

kmp算法详解

从头到尾彻底理解KMP 此文转自神的博客  http://blog.youkuaiyun.com/v_july_v/article/details/7041827# 作者:July 时间:最初写于2011年12月,2014年7月21日晚10点 全部删除重写成此文,随后的半个多月不断反复改进。后收录于新书《编程之法:面试和算法心得》第4.4节中。 1. 引言     本KMP原文最初写于2

楠先生 4万+

大话 KMP 算法

LeetCode上有一题,简单难度的,以下是原题 这个题目应该刷LeetCode的同学大部分都刷到过,比较荒谬的是可以直接用 indexOf 方法实现,并且是最优的解法,看到评论以后一片哗然,大家扯到最多的是这道题就应该用KMP来做,如果用KMP做那这道题应该是困难级别的。所以看了这些评论以后,决定自己去摸索一下KMP的算法,以及大概其实现原理。 网上找了很多关于解释KMP算法的...

lmx125254的博客 3833

kmp算法和kmp的优化

一、kmp是什么 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。 简单来...

harry12138小白的博客 1498
上一篇: 串
下一篇: 树
PAT-python-zjw
博客等级 码龄10年 381粉丝 408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值