4.6.KMP算法(旧版下)-朴素模式匹配算法的优化

《数据结构》KMP 串的模式匹配 题目 给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出。如果找不到,则输出“Not Found”。 本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下: 数据0:小规模字符串,测试基本正确性; 数据1:随机数据,String 长度为 105^55​​​ ... 阅读详情

一.绪论:

当主串字符和模式串字符不匹配时会执行j=next[j]来改变模式串的指针,但主串的指针不变。


二.求模式串的next数组:

1.例一:

如模式串abcabd,当第六个字符d匹配失败时,此时主串中前五个字符abcab都与模式串匹配成功,因此需要后移模式串:

模式串后移一个位置,显然主串中第二个字符b与模式串中第一个字符a不匹配,继续后移:

模式串再后移一个位置,显然主串中第三个字符c与模式串中第一个字符a不匹配,继续后移:

模式串再再后移一个位置,显然主串中第四个字符a与模式串中第一个字符a匹配,无需后移:

因此当模式串指针指向的第六个字符匹配失败时要让模式串指针从6回溯到3即next[6]为3:

2.例二:

如模式串abababcdef,当在第七个字符c匹配失败时,此时模式串中的前六个字符都能与主串匹配成功,最终需要模式串向右移动:

模式串后移一个位置,显然主串第二个字符b与模式串第一个字符a匹配失败,因此继续后移模式串:

模式串再后移一个位置,此时主串第三个字符a与模式串第一个字符a匹配成功,此时模式串无需后移:

因此当模式串指针指向的第七个字符匹配失败时要让模式串指针从7回溯到5即next[7]为5。
如果把模式串继续后移两个位置,此时模式串指针指向模式串的第三个字符a,而且模式串的第一个字符a和第二个字符b都可以匹配成功:

假设主串中字符如下图所示,此时主串指针i指向的字符和模式串第七个字符c不匹配,而且继续往后匹配,主串的c和模式串的第五个字符a匹配失败,如果按照刚才的next[7]为5,配对如下:

因此结论如下:如果有更长的一段能够匹配的上的话,优先考虑更长的这种情况

3.例三:

如模式串为aaaabcd,在第五个字符b和主串匹配失败,可知前四个字符aaaa都可以与主串匹配成功,此时需要把模式串后移:

模式串后移一个位置后,模式串前三个字符aaa都可以与主串匹配成功,此时应该让模式串里的指针回溯到4,判断是否能与主串匹配成功即next[5]为4:

显然,如果模式串再往后移一个位置,模式串和主串开头也能够匹配上,但一定能匹配成功的字符只有模式串中的前两个字符aa,主串中第五个字符还不确定是否为a,不往后移之前一定能匹配成功的字符有三个aaa,因此暂时不移动模式串较好;

4.例四:

如模式串为abcdefg,在第五个字符e时和主串匹配失败,因此模式串前4个字符abcd可以匹配成功,因此模式串需要后移:

模式串后移一个位置后,显然模式串第一个字符a与主串第二个字符b就不匹配,因此继续后移:

模式串后移一个位置后,显然模式串第一个字符a与主串第三个字符c就不匹配,因此继续后移:

模式串后移一个位置后,显然模式串第一个字符a与主串第四个字符d就不匹配,因此继续后移:

模式串后移一个位置后,此时模式串第一个字符a可能与主串第五个字符匹配成功,因此需要模式串指针从5回溯到1即next[5]为1,这个例子的特殊之处在于前几个例子中总是能找到主串已经确定的一些字符和模式串开始的字符能够匹配成功,但这个例子中主串中确定的字符中,无论后移几次模式串,都无法与主串匹配成功,所以之后需要判断主串中未知的字符能否与模式串中的字符匹配成功:

5.例五:

如模式串为abcabd,当检查到模式串中第一个字符a就发现与主串第一个字符匹配失败,此时模式串无需移动,需要检查主串的第二个字符能否与模式串中第一个字符a匹配成功:

如下图所示,此时可以先把模式串里的指针设为0:

然后主串指针和模式串指针同时加一,最终next[1]为0:

6.代码:

7.总结:

a.对于串的前缀,如模式串中第一个字符到第六个字符ababab,以ab为一段,第一个字符到第四个字符abab就是ababab的一个前缀,不包含最后一段;

b.对于串的后缀,如主串中的第一个字符到第六个字符ababab,以ab为一段,第三个字符到第六个字符abab就是ababab的一个后缀,不包含第一段;

c.注:前缀和后缀中前缀和后缀不一定只有一个字符组成,如ababab中a,ab,aba等都可以是它的前缀,后缀同理;

d.对于next[j]=S的长度等于前/后缀对的上的最大长度加一,如模式串中的S串(ababab),前缀最大就是abab,长度为4,所以S的最大长度为4+1等于5;

再比如上述图中右边的例子:模式串指针j在第五个字符时匹配失败,那么此时就要看前面的j-1个字符,由这些字符组成的字符串S(S为abcd),此时要找主串的后缀和模式串的前缀对的上的串的最大长度,先主串中从abcd后面开始取后缀d,再在模式串从abcd前面开始取前缀a,发现对不上,之后,主串中从abcd后面开始取后缀cd,模式串从abcd前面开始取前缀ab,发现还是对不上,之后,主串中从abcd后面开始取后缀bcd,模式串从abcd前面开始取前缀abc,发现还是对不上,现在主串和模式串就都不能再取了,因为主串取后缀,取后缀不能包含第一个字符,主串一共4个字符,从后面已经取了3个字符,第一个字符不能再取,模式串取前缀,取前缀不能包含最后一个字符,模式串一共4个字符,从前面已经取了3个字符,最后一个字符不能再取,所以S串最大长度为0,加一为1,因此next[5]为1:

比较特殊的情况,就是例五:


二.练习:求模式串的next数组

1.题目一:

思路:首先可以确定j为1时有next[j]为0;(其实next[1]必定为0,next[2]必定为1)

如果当 j为2即模式串指针指向的模式串第二个字符b时发现匹配失败,按照规则,第二个字符之前即第一个字符a组成的串S(只有一个a,a是第一个字符,也是最后一个字符),显然S串的前缀是空串(长度为0),因为前缀不包含最后一个字符,后缀也是一个空串(长度为0),因为主串中只有a与 模式串匹配成功,后缀不包含第一个字符,所以S串最大长度为0,加一为1,因此next[2]为1;

如果当j为3即模式串指针指向的模式串第三个字符a时发现匹配失败,说明第三个字符之前即ab都与主串匹配成功即串S为ab,串S的一个字符记为ab,显然串S没有前缀和后缀(串S取一个字符时S串最大长度也为0,当S串前缀为a时,就不能要b,对应的主串后缀就是b,就不能要a,显然前缀和后缀匹配失败,S串最大长度也为0),所以S串最大长度为0,加一为1,因此next[3]为1;

如果当j为4即模式串指针指向的模式串第四个字符b时发现匹配失败,说明第四个字符之前即aba都与主串匹配成功即串S为aba,此时前缀取一个字符a,后缀取一个字符a,只剩下b,所以S串最大长度为1,加一为2,因此next[4]为2;(其实前缀可以依次是a,ab,对应的后缀依次是a,ba,将前缀和后缀分别看成两个集合,这两个集合的交集只有一个a,所以S串最大长度为1,前缀和后缀也可以取aba,此时没有前缀和后缀,但这样的话S串最大长度为0,加一为1,因此next[4]为1,显然比next[4]为2低效,不可取,其他取前缀和后缀的原理同理,而且取前/后缀要考虑匹配最多的取);

如果当j为5即模式串指针指向的模式串第五个字符a时发现匹配失败,说明第五个字符之前即abab都与主串匹配成功即串S为abab,取前缀为ab,后缀也取ab(此时主串中有abab),显然前缀和后缀匹配成功,模式串中取了ab,长度为2,因此S串最大长度为2,加一为3,因此next[5]为3;

如果当j为6即模式串指针指向的模式串第六个字符a时发现匹配失败,说明第六个字符之前即ababa都与主串匹配成功即串S为ababa,如果前缀取aba,后缀也取aba(此时主串中有ababa,取的是第一个字符到第三个字符的aba,因为可以与模式串匹配上的字符多,不是第三个字符到第五个字符的aba),前缀和后缀可以匹配成功,模式串中取了aba,长度为3,因此S串最大长度为3,加一为4,因此next[6]为4;

2.题目二:

思路:首先可以确定j为1时有next[j]为0;可以确定j为2时有next[j]为1;

如果当j为3即模式串指针指向的模式串第三个字符a时发现匹配失败,说明第三个字符之前即aa都与主串匹配成功即串S为aa,显然前/后缀能匹配的上的最长的长度为1(取a,如果取aa的话就没有前缀和后缀了,此时前缀和后缀的长度为0),因此S串最大长度为1,加一为2,因此next[3]为2;

如果当j为4即模式串指针指向的模式串第四个字符a时发现匹配失败,说明第四个字符之前即aaa都与主串匹配成功即串S为aaa,显然前/后缀能匹配的上的最长的长度为2(取aa,如果取aaa的话前/后缀的长度为0,取a的话主串与模式串能匹配的字符最少,只有一个,不可取),因此S串最大长度为2,加一为3,因此next[4]为3;

如果当j为5即模式串指针指向的模式串第五个字符b时发现匹配失败,说明第五个字符之前即aaaa都与主串匹配成功即串S为aaaa,显然前/后缀能匹配的上的最长的长度为3(取aaa,前缀和后缀都能匹配上),因此S串最大长度为3,加一为4,因此next[5]为4。


三.求模式串的next数组的代码:

1.演示:

a.第二条求next[j]的语句中:等号左边的是模式串里的字符(即前缀),注意下标k-1,等号右边的是主串里的字符(即后缀),注意下标j-1,他们之间能够匹配的上的(相等)最大长度;k为模式串的指针,j为主串的指针;注意最长相等前后缀长度加一

b.第三条求next[j]的语句中:其他情况一般指前缀和后缀匹配失败时;

2.代码:

时间复杂度分析:从Index_KMP函数(Index_KMP函数中i为主串指针,i初始值为1,j为模式串指针,j初始值为1)开始,之后到get_next函数,然后到get_next函数里的while循环,其中i初始值为1,j初始值为0,T就是模式串,T.length就是模式串的长度,get_next函数里的while循环要循环1到T.length-1次,设T.length-1为m,那么get_next函数的while循环的时间复杂度为O(m),所以get_next函数的时间复杂度为O(m),执行完get_next函数,到了Index_KMP函数里的while循环,不需要考虑j,因为j是模式串的指针,主串的长度一般远大于模式串的长度,因此i的变化远大于j的变化,所以j就可以忽略不计了,主串指针i永远不回溯,最多不会超过主串的最后一个位置,所以while循环执行1到S.length次(S代表主串,S.length代表主串的长度),设主串的长度为n,那么Index_KMP函数里的while循环的时间复杂度为O(n),所以Index_KMP函数的时间复杂度为O(n),由此可得,Index_KMP函数的平均时间复杂度为O( (n+m)/2 ),等价于O(n+m)。


四.总结:

1.KMP算法让主串指针不回溯,只让模式串指针回溯;

2.朴素算法是主串指针和模式串指针都需要回溯;


【数据结构】朴素模式匹配 & KMP算法 💯KMP算法就是消除指针i的回溯,让i指针只进不退,而只移动模式串指针指向位置的方法,由于此时"$p_1...p_{k-1}$"和"$p_{j-k+1}..p_j$"都是相同的,所以这时候相当于将$j1$指针指向前缀,$j1$不断前移,$j2$指针指向后缀,$j2$不断后移(这里j1是主动指针,而j2相当于从动指针),因为只要保证他们一直为之前的公共前缀,就可以不用在意这$k'-1$长度的子串,这样主要考虑的就是要找到前缀中的一个值 $p_k'=p_j$ 阅读详情

相关推荐

KMP模式匹配算法

朴素的模式匹配算法 对主串的每一个字符作为子串的开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做需匹配长度的小循环,直到匹配成功或者全部遍历完成为止 示例程序(朴素的模式匹配)int Index(char *S, char *T) { int i, j; // 直到遍历主串完成或者需匹配字符串全部匹配成功 for (i = 0, j = 0; i < (in

没有梦想,何必远方 4531

数据结构——串(朴素的模式匹配算法、KMP模式匹配算法)

数据结构——串(朴素的模式匹配算法、KMP模式匹配算法) 键盘上的钢琴师_v5 提示:以下内容不适合零基础人员,仅供笔者复习之用。 概要: 串是由零个或多个字符组成的有限序列,又名叫字符串。 一、串的比较 给定两个串,s = "a1a2.....an",t="b1b2....bm",当满足以下条件之一时,s<t。 n<m,且ai = bi(i=1,2,.....,n)。例如,s="hap",t="happy",就有s<t。 存在某个k<=min(m,n),使得...

cxu123321的博客 3160

字符串的模式匹配 (朴素模式匹配算法 ,KMP算法)

字符串的模式匹配 寻找字符串p在字符串t中首次出现的起始位置 字符串的顺序存储 typedef struct { char str[MAXSIZE]; int length; }seqstring; 朴素的模式匹配算法 基本思想:用p中的每一个字符去与t中的字符一一比较。 模式p 正文 t 如果匹配成功,则返回p在t中首次出现的起始位置 如果匹配不成功则返回-1 最坏情况比...

( :3 ) 2579

[入门必看]数据结构4.2:串的模式匹配

数据结构4.2:串的模式匹配

m0_58991879的博客 1360

KMP模式匹配算法原理分析、next数组优化及java实现

朴素的模式匹配算法通过对主串进行回溯,每次在匹配不成功时回溯到主串的i-j+2的位置(i为主串中匹配失败的位置,j为模式串中匹配失败的位置,其中模式串字符数组从位置1开始),KMP算法采用next数组,避免对主串的回溯,主要分析模式字符串的特征,确定在匹配失败情况下通过next数组获取应该模式串应该回溯的位置,next数组目的在于当主串和模式串的字符匹配发生失败时,可以获取模式串回溯的位置,从新和主串进行匹配

code4grow专栏 3930

KMP最经典版本2.9.3.1428版

KMP是来自韩国的全能播放器,现在虽然还在开发,但原作者已转投potplayer研发,此版本是原作者最后开发的版本,XP下无敌的存在。解压密码:www.nautc.com

串的模式匹配(选择题)(期末数据结构复习9)

next 和 nextval 数组

qq_61369552的博客 738

重庆大学数据结构实验报告,串的操作与KMP模式匹配算法源码及结果截屏

这是重庆大学数据结构实验报告,题目是串的操作与KMP模式匹配算法。里面有完整的实验流程,包括源码及结果截屏

串的模式匹配算法(朴素算法、KMP算法及其优化)

本文介绍了两种模式匹配算法:朴素算法(BF算法)和KMP算法。朴素算法通过逐个字符比较实现,时间复杂度为O(nm)。KMP算法利用next数组避免主串指针回溯,提高了效率。重点讲解了next数组的计算方法,包括手动计算和代码实现,并提出了KMP算法的优化版本,通过nextval数组进一步减少不必要的比较。优化后的KMP算法在处理重复字符模式串时表现更优。

主要更新数据结构与算法相关内容 1287

老版kmpplayer

播放器

Linux音频调试实战:ALSA架构与tinymix工具的高级应用技巧

本文深入探讨了Linux音频调试的核心技术,重点解析了ALSA架构下音频信号的路由与混合机制。通过介绍轻量级命令行工具tinymix的高级应用技巧,指导开发者如何精准排查无声、音量异常、多路音频共存等复杂问题,并分享编写自动化测试脚本以提升嵌入式及智能设备音频开发效率的实战方法。

weixin_29210727的博客 101

C/C++——朴素的模式匹配算法和KMP模式匹配算法

朴素的模式匹配算法其实就是一个一个往下匹配,没有任何优化,在好的情况下时间复杂度为O(n+m),在最求的情况下时间复杂度为O((n-m+1)*m)。 代码实现://在主串s中找子串t,若找到返回字串在主串中的索引;若没找到返回-1 #include <iostream> #include <string>using namespace std;int Index(string s, string

Learn From The Masters 3693

别再混淆了!一文彻底搞懂STM32的BootROM、BootLoader和启动模式(附启动流程图)

本文深入解析STM32的启动机制,详细讲解BootROM、BootLoader与启动模式的区别与联系,并提供实战指南。通过清晰的启动流程图和配置示例,帮助开发者彻底理解STM32启动流程,解决常见的启动问题,提升嵌入式开发效率。

weixin_33728268的博客 538

朴素模式匹配算法和KMP匹配算法 详细

朴素模式匹配算法和KMP匹配算法 一、朴素模式 假设我们要从主串S=”goodgoogle"中找到子串T=“google"的位置,步骤如下: i表示主串的当前位置下标,j表示子串的当前位置下标,如上图在第一轮比较(i=1开始)中j=4和i=4的位置不匹配,接下来就要指针回退,从i=2开始比较,如下: 如此反复直到比较到 i =(主串长度-子串长度+1)的位置或者 j = 子串的长度 就退出比较...

weixin_44026997的博客 2981

R以及Rstudio超详细安装教程(包括安装过程中出现的问题)

R安装及Rstudio安装,以及安装中出现的问题

2301_76908257的博客 1万+

【清华大学软院】15-19年推免试题历年整理

整理的题目为清软预推免机试(外校)硕士机考题目。 年代 题目1 题目2 题目3 2019 质因数分解 二叉搜索树 区间DP(折叠字符串) 2018 日期转换 高精度模拟 区间DP(戳气球) 2017 进制素数 被遗漏的数字 DP(收集苹果) 2016 大数运算 DP DFS 2015 进制素数: http://acm.hdu.edu.cn/showproblem.php?pid=1230 2017年题目(这个是找的最准确的题目): 1题见【链接】 2题见【链接】

云端筑梦师 2256

字符串的模式匹配(朴素模式匹配算法,KMP算法)

假设主串长度为n,模式串长度为m.朴素模式匹配算法︰将主串中所有长度为m的子串依次与模式串对比,直到找到一个完全匹配的子串,或所有的子串都不匹配为止。最多对比n-m+1个子串。

jungleirim的博客 1534

CocosCreator | 自定义启动页之H5

01 效果对比 默认启动页: 自定义启动页: 02 启动页存在的意义 我们在 creator 中的开发的游戏都是基于 cocos engine,所以在展示我们的游戏之前,是必须要先加载 cocos engine,然后才是我们自己的业务代码 流程图如下: 而构建完成后未精简的 cocos engine 代码为 1.9M 如果再加上物理相关代码的话,一共是2M 别忘了,我们自己的首场景也要加载过程哦 所以,从游戏启动,到真...

Valiancer 5897

数据结构之字符串的模式匹配(朴素算法+KMP)

字符串的模式匹配是计算机领域中的经典问题之一,朴素算法和KMP算法分别代表了简单直接和高效智能的两种解决方案。在实际应用中,根据具体场景选择合适的算法可以有效提高程序的执行效率。

qq_62642080的博客 1237

Ubuntu20.04安装Eigen3.3.7、模板类Sophus和Ceres

Sophus的使用必须依赖3.3以上的Eigen版本。如果版本太低,Sophus库将无法安装使用。

qq_62964142的博客 3422

DPM|03Injection设置

摘要:本文介绍了CFD软件Fluent中粒子注入的设置方法。粒子注入是将离散颗粒引入连续相的过程,可用于模拟灰尘、燃料液滴等。设置流程包括:选择粒子类型(质量less、惰性等)、定义注入点属性(坐标、时间、粒径等)、处理多组分粒子、使用文本文件批量定义复杂注入。文中还详细说明了要考虑的湍流影响,包括随机追踪法模拟湍流扩散,以及粒子旋转建模等注意事项。最后介绍了多种注入类型和粒子类型,并强调在湍流系统中需设置足够的尝试次数以确保结果准确性。

qq_28258217的博客 2229

4.5.KMP算法(旧版上)-朴素模式匹配算法的优化

如果在j为5时匹配失败(j为模式串的指针),那么主串中分别以第5个字符即g,第6个字符即o,第7个字符即o开头的子串都不可能与模式串匹配,但第8个字符即g开头的子串有可能与模式串匹配成功,因为第8个字符即g能与模式串第一个字符g匹配上,而且在匹配过程中只是说明了子串中第9个字符与模式串中j为5时对应的字符不匹配,并没有说明子串中第9个字符与模式串中第二个字符不匹配,接下来。由于i和j指向的字符不匹配(不相等),根据j=next[j],会让j=next[1],此时j为0,下一轮循环时发现j为0,

ADCvbV的博客 1305

STM32 CAN发送丢包?3个邮箱轮询法实测有效(附代码)

本文深入分析了STM32 CAN总线发送丢包的根本原因,指出其内置CAN控制器的三个发送邮箱是硬件瓶颈。针对高负载场景,提供了实测有效的优化方案,重点介绍了非阻塞的邮箱状态轮询法,该方法通过主动轮询三个邮箱的空闲状态,充分利用硬件资源,显著提升发送稳定性并避免任务阻塞。文中附有可直接使用的示例代码。

weixin_29189381的博客 195

【数据结构】串的模式匹配(KMP+朴素模式匹配)

2.对其他的next:在不匹配的位置前,划一条分界线,模式串一步步往后退,直到分界线前能对上,或模式串完全跨过分界线为止。从模式串本身的结构着手,若已匹配相等的前缀序列中有某个后缀正好是模式串的前缀,则可将模式串向后滑动到与这些相等字符对齐的位置。3.若 i 和 j 所指字符不相同,j 回到模式串第一个字符,i 指向下一个子串起始位置;​ 当模式串中第a个元素匹配失败时,令主串指针i不变,模式串指针j=b。当模式串的第j个字符失配时,从模式串的第next[j]个继续往后匹配。

m0_61628700的博客 1783

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【串】串的模式匹配算法(BF+KMP)(C语言)

串的模式匹配算法(C语言) 1.字符串的初始化函数 定义一个字符数组S,我们用第0位来存储该字符串的长度,其余位置顺序存储该字符串。(字符串的首位从1开始) 代码实例: #include <stdio.h> #include <string.h> #define N 100 /*静态定义数组的长度*/ typedef char String[N]; // String s1 等价于 char s1[N] int StrAssign(String T,

weixin_51424157的博客 3968

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

KMP算法——串的朴素模式匹配算法的优化、KMP算法的优化

KMP算法——串的朴素模式匹配算法的优化、KMP算法的优化什么是串的模式匹配朴素(简单)模式匹配算法KMP算法——串的朴素模式匹配算法的优化KMP算法优化——nextval数组 什么是串的模式匹配 串的模式匹配:在主串中找到与模式串相同的字串,并返回其所在位置 例如: 主串:S='sdkjfklajsflkjlaskjf' 字串:'sdk'、'dkj'、'jfk'........ 模式串:'as'、'flk' 朴素(简单)模式匹配算法 int Index(SString S,SString T){ in

baidu_41803143的博客 464

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: 4.5.KMP算法(旧版上)-朴素模式匹配算法的优化
下一篇: 5.1.树的定义和基本术语
巧克力拌面
博客等级 码龄3年 1153粉丝 282原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值