模式匹配(Java)


模式匹配

模式匹配是数据结构中字符串的一种基本运算。
由于字符串我们学习过了,大部分操作都比较清楚,但是模式匹配相对来说操作稍微有些难度,所以我们在这里简单的进行讲述。
模式匹配的具体操作如下:给定一个子串(也称为模式串),要求在某个字符串中找出与该子串相同的所有子串。

我们在此讲述2种常见实现:

  1. 暴力匹配
  2. KMP算法

暴力匹配(BF算法)

主要思想:从主串的第一个元素开始,与模式串第一个元素相比较,相等则逐一比较,若有不同元素,主串回溯至下一个元素,与模式串的一个元素相比较,依次循环。
为了方便讲解,我们针对下面的案例来进行讲解:
要求在寻找模式串第一次在主串出现的位置,未找到则返回-1。

我们把这个过程分为5步:

  1. 首先,我们需要将主串进行遍历。
  2. 主串的每一次遍历中,与模式串进行比较,若相同比较下一个元素。
  3. 如果模式串比较结束,说明模式串成功匹配,返回主串当前下标。
  4. 如果两元素不同,说明此处匹配失败,主串继续遍历下一个元素。
  5. 若主串遍历结束,仍未成功匹配,则说明主串中无该模式串,返回-1。

我们举个例子演示一下,假设主串abdabcda,模式串abcd,模式匹配后应当得到3。

主串当前遍历到的元素/下标 主串的元素 模式串元素 比较
a/0 a a 相等,比较下一个元素
a/0 b b 相等,比较下一个元素
a/0 d c 不相等,回溯,继续遍历主串
b/1 b a 不相等,回溯,继续遍历主串
d/2 d a 不相等,回溯,继续遍历主串
a/3 a a 相等,比较下一个元素
a/3 b b 相等,比较下一个元素
a/3 c c 相等,比较下一个元素
a/3 d d 相等,比较下一个元素
a/3 a \0 模式串比较结束,匹配成功

完整代码如下

public static int bruteForceStringMatch(String str, String pattern) {//如果主串长度不小于模式串,则进入模式匹配if (str.length() >= pattern.length()) {//获取两串的字符数组,以便遍历char strOfChars[] = str.toCharArray();char patternOfChars[] = pattern.toCharArray();//两个循环控制变量int loopOfStr, loopOfPattern;//遍历主串,任意一串遍历结束,则匹配结束for (loopOfStr = 0, loopOfPattern = 0 ; loopOfStr < str.length() && loopOfPattern < pattern.length() ;) {//如果两元素相同,比较下一个元素if (strOfChars[loopOfStr] == patternOfChars[loopOfPattern]) {loopOfStr++;loopOfPattern++;} else {loopOfStr -= loopOfPattern - 1;//主串下标回溯loopOfPattern = 0;//模式串下标重置}}//模式串匹配结束,表示匹配成功if (loopOfPattern == pattern.length()) {return loopOfStr - loopOfPattern;//主串中模式串第一次出现的位置}}//模式匹配失败return -1;
}

时间复杂度设主串和模式串的长度分别为m,n,则它在最坏情况下的时间复杂度是O(m*n)。


KMP算法

KMP算法

主要解决了BF算法的回溯问题,从而降低了时间复杂度。他的时间复杂度为O(m+n)。

主要思想:KMP算法的关键是利用匹配失败后的信息, 尽量减小两串的匹配次数,以达到快速匹配的目的。通过一个next[]数组寻找最长且相同的前缀和后缀,以减少匹配次数。

我们举个例子,来看看KMP算法是怎么工作的
主串:AAAAAB
模式串:AAAB

BF算法求解时:

我们在匹配时会发现,第一次中模式串与主串只有第四个元素不相同,其他元素相同。同时我们发现,模式串中前3个元素是相同的,我们不妨想想,第二次匹配时,模式串的前两个字母还有必要去比较吗?

显然这两次的比较是没有必要的,那么我们就要借助next[]数组来帮忙了。

模式串AAAB的next[]数组值为{-1,0,1,2},我们在后面会讲解next[]数组如何求取。我们在第一次匹配时,第四个元素不同,模式串下标移至next[3]的位置,即2,也就是下一次从第三个A的位置开始匹配,直接跳过了前两个A,减少了匹配时比较次数。之后是类似的操作。

我们将KMP算法匹配的过程也分为5步:

  1. 首先,我们需要将主串进行遍历。
  2. 主串的每一次遍历中,与模式串进行比较,若相同比较下一个元素。
  3. 如果模式串比较结束,说明模式串成功匹配,返回主串当前下标。
  4. 如果两元素不同,说明此处匹配失败,模式串下标更新至next[]值的位置,主串继续遍历下一个元素。
  5. 若主串遍历结束,仍未成功匹配,则说明主串中无该模式串,返回-1。:

KMP算法求解时:

KMP算法代码如下

public static int KMP(String str, String pattern) {//如果主串长度不小于模式串,则进入模式匹配if (str.length() >= pattern.length()) {//获取next数组int next[] = getNext(pattern);//获取两串的字符数组,以便遍历char strOfChars[] = str.toCharArray();char patternOfChars[] = pattern.toCharArray();//两个循环控制变量int loopOfStr, loopOfPattern;//遍历主串,任意一串遍历结束,则匹配结束for (loopOfStr = 0, loopOfPattern = 0 ; loopOfStr < str.length() && loopOfPattern < pattern.length() ;) {//如果两元素相同,或模式串全部匹配失败,比较下一个元素if (loopOfPattern == -1 || strOfChars[loopOfStr] == patternOfChars[loopOfPattern]) {loopOfStr++;loopOfPattern++;} else {loopOfPattern = next[loopOfPattern];//模式串下标置为next值}}//模式串匹配结束,表示匹配成功if (loopOfPattern == pattern.length()) {return loopOfStr - loopOfPattern;//主串中模式串第一次出现的位置}}//模式匹配失败return -1;
}

next[ ]数组

经过上面的例子我们发现,next[]数组的求取,是KMP算法的最重要的一环,那么next[]数组究竟应该怎么求呢?

next[]数组实际上存储了模式串每一个元素的前缀与后缀相同的最大长度(不包括自身),因此在匹配时造成了一种跳跃式匹配。我们还是用上面的模式串来解释:AAAB

注意:我们默认把第一个元素的next值设为-1

前缀 后缀 最大长度
0 -1
1 0
2 A A 1
3 A,AA AA,A 2

next[loopOfPattern] = nextValue, 我们这里利用递归的思想求出next[loopOfPattern+1]的值:

  1. 如果p[loopOfPattern] = p[nextValue],则next[nexValue+1] = next[nextValue] + 1;
  2. 如果p[loopOfPattern] != p[nextValue],则令nextValue = next[nextValue],如果此时p[loopOfPattern] == p[nextValue],则next[loopOfPattern+1] = nextValue+1;
  3. 如果不相等,则继续递归前缀索引,令nextValue=next[nextValue],继续判断,直至nextValue=-1(即nextValue=next[0])或者p[loopOfPattern]=p[nextValue]为止

国际惯例,上代码


getNext方法的实现

private static int[] getNext(String pattern)
{//获取两串的字符数组,以便遍历char patternOfChars[] = pattern.toCharArray();//创建next数组int[] next = new int[pattern.length()];int nextValue = -1, loopOfPattern = 0;//初始化next值及模式串下标next[0] = -1;//这里采用-1做标识while(loopOfPattern < pattern.length() -1){//获取next数组if(nextValue == -1 || patternOfChars[loopOfPattern] == patternOfChars[nextValue]){nextValue++;loopOfPattern++;next[loopOfPattern] = nextValue;} else {nextValue = next[nextValue];}}return next;
}

模式匹配(Java)——烤馍片算法(KMP算法)相关推荐

  1. 字符串匹配算法(BF算法KMP算法)

    字符串匹配算法 暴力匹配(BF)算法 KMP算法 next数组 求next数组的练习 next数组的优化(nextval数组) 练习 暴力匹配(BF)算法 BF算法,即暴力(Brute Force)算 ...

  2. 算法 - KMP算法原理顿悟有感

    算法 - KMP算法原理顿悟有感 KMP? KMP核心思想 举个栗子 上点代码 next数组 (1)若P~j~ == P~t~ (2) 若P~j~ 和 P~t~不相等 改进上面的KMP算法 nextv ...

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

    字符串的模式匹配 寻找字符串p在字符串t中首次出现的起始位置 字符串的顺序存储 typedef struct {char str[MAXSIZE];int length; }seqstring; 朴素 ...

  4. 字符串的模式匹配--BF算法KMP算法

    BF算法是基于主串指针回溯,重新与子串进行逐字符进行比较,主串为S什么要进行回溯呢,原因在于模式P中存在相同的字符或者说由字符(串)存在重复(模式的部分匹配性质),设想如果模式P中字符各不相同,主串就 ...

  5. 详解图示+例题演练——BF算法+KMP算法基本原理

    KMP算法一直让我们又爱又恨,难以理解却又效率很高. 看了看网上的KMP教程,无论是博客还是视频,大多以文字和逻辑推导的方式呈现,纷繁复杂,晦涩难懂.这会让我们在初学时多走很多弯路. 人类接受知识最直 ...

  6. (C语言)数据结构算法-病毒感染检测(BF算法KMP算法)

    病毒感染检测: 医学研究者最近发现了某些新病毒,得知它们的DNA序列都是环状的.为了快速检测出患者是否感染了相应的病毒,研究者将患者的DNA和病毒的DNA均表示成一些字母组成的字符串序列,然后检测某种 ...

  7. 用C语言实现KMP算法,KMP算法 纯C实现

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 我自己写的KMP算法: int nt[256]; void get_next1(char* T, int next[], int tlen) { int  ...

  8. 字符串算法——KMP算法C++详解

    简介 KMP 算法是 D.E.Knuth.J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法.该算法相对于 Bru ...

  9. Knuth-Morris-Pratt 算法(KMP算法)

    Knuth-Morris-Pratt 算法,简称 \text{KMP}KMP 算法,由 \text{Donald Knuth}Donald Knuth.\text{James H. Morris}Ja ...

最新文章

  1. 微软宣布在Azure API管理中预览OpenAPI规范V3
  2. 如何完美隐藏Disposable的存储和销毁过程(一)
  3. idea中修改代码大小设置
  4. JS-DOM ~ 03. 子节点的操作、style.样式和属性、dom元素的创建方法及操作、14个例题、主要是利用js直接控制html属性...
  5. git常用命令流程图
  6. php 调用 com,PHP调用COM函数
  7. 逐行粒度的vuex源码分析
  8. Function的常用属性和方法
  9. Redisbook学习笔记(1)字典(2)
  10. 一个鼠标控制2台电脑简单方法
  11. 计算机视觉及OpenCV入门简介
  12. Cortex-M3 (NXP LPC1788)之GPIO
  13. 儿童拼图游戏软件测试,宝宝益智英语字母拼图大全(测试版)
  14. 玩转用户身份权益——详解闲鱼身份权益体系的实现
  15. Bootstrap3基础 btn-xs/sm... 按钮的四种大小
  16. 搞个气氛 用MATLAB画一棵精致的圣诞树
  17. CODESYS自动化仿真软件如何与EtherNet IP工业RID读写器|读卡器CK-RF102AN-E01联机工作
  18. KVR16N11S8/4-SP 内存是什么型号
  19. Excel(Office)哪一版最好用?
  20. 怎么制作升温曲线图_PCBA制造过程中几种典型的温度曲线

热门文章

  1. 11个激发LOGO 标志设计灵感的网站
  2. C#实战积累:常用的lambda表达式整理
  3. Win7专业版 下安装ArcGIS 9.3总结
  4. 深度学习也可以取悦女友
  5. 【C语言】带你回顾C语言全部运算符(详解)
  6. 奇葩算法系列——量子猴子排序
  7. 一首很好听的歌曲(Unique)
  8. Java实现 LeetCode 389 找不同
  9. 百度云服务器有哪些优势?
  10. 关于Altium Designer 20 的捕抓功能的讲解