字符串与模式匹配算法(三):KMP算法
一、KMP算法介绍
KMP算法与前面的MP算法一脉相承,都是充分利用先前匹配的过程中已经得到的结果来避免频繁回溯。回顾一下MP算法,如下图的模式串偏移,当前模式字符串P的左端的p0与目标字符串T中tj位置对齐。从左向右逐个进行比较,发现 pi 处的字符a 与 tj+1 处字符b发生失配。同时也表明 P(p0,p1,...,pi-1) 与 T'(tj,tj+1,...,tj+i-1) 是完全匹配的,这一部分子串在图中用字母u标示出。由于发生失配,随即移动模式字符串并进行下一轮的比较。此时,很自然地希望移动之后的结果可以使得模式字符串P中的一个前缀v,可以匹配到子串u的某一部分后缀。所以MP算法引入一个mpNext数组,并用它来对P中最长前缀进行标记。然后根据PmpNext[i] = c 和 Ti+j = b 之间展开下一轮比较。

在MP算法的基础上再推进一步,继续前面的过程,当模式字符串P完成一次移动后,接下来马上要进行的工作是比较字符 b 和 c,为了避免随之而来的一次失配,在仅仅知道模式字符串P的情况下,保证一次移动后,紧随着前缀字符串v之后的那个字符c不等于原来失配的字符a(满足这个条件的最长前缀v是字符串u的加标边际)。KMP算法需要对mpNext表中符合要求的加标边际进行标识,符合要求指的是:① v可以匹配到u中某个后缀的最长前缀; ② 紧跟在v后面的字符c不同于紧跟在u后面的字符a。
二、kmpNext表的规则
在mpNext表生成的基础上,建立kmpNext表的规则分为4种情况,其中 1≤j≤m-1:
如果 mpNext[j] = 0 且 pj = p0,则令kmpNext[j] = -1;
如果 mpNext[j] = 0 且 pj ≠ p0,则令kmpNext[j] = 0;
如果 mpNext[j] ≠ 0 且 pj ≠ pmpNext[j],则令kmpNext[j] = mpNext[j];
如果 mpNext[j] ≠ 0 且 pj = pmpNext[j],则用mpNext[j]中的值替换原来mpNext[j]中的j值,直到情况转换为前面3种情况的一种,从而递归求解kmpNext[j]。
在 j =0 的位置同样是 -1,并令kmpNext[m] = mpNext[m],m是模式串P的长度。kmpNext[m]的值也是指示了后续进行匹配而需要将模式字符串移动的位数。
kmpNext表:
|
j |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
p(j) |
c |
a |
a |
t |
c |
a |
t |
|
|
mpNext[j] |
-1 |
0 |
0 |
0 |
0 |
1 |
2 |
0 |
|
kmpNext[j] |
-1 |
0 |
0 |
0 |
-1 |
0 |
2 |
0 |
三、代码
1 public void preKmp(char[] x, int m, int[] kmpNext) {
2 int i, j;
3 i = 0;
4 j = kmpNext[0] = -1;
5 while(i < m-1) {
6 while (j > -1 && x[i] != x[j])
7 j = kmpNext[j];
8 i++;
9 j++;
10 if (x[i] == x[j])
11 kmpNext[i] = kmpNext[j];
12 else
13 kmpNext[i] = j;
14 }
15 }
16
17 public void kmp(String p, String t) {
18 int m = p.length();
19 int n = t.length();
20
21 if (m > n) {
22 System.err.println("Unsuccessful match!");
23 return;
24 }
25
26 char[] x = p.toCharArray();
27 char[] y = t.toCharArray();
28
29 int i = 0;
30 int j = 0;
31 int[] kmpNext = new int[m+1];
32 preKmp(x, m, kmpNext);
33
34 while (j < n) {
35 while (i > -1 && x[i] != y[j])
36 i = kmpNext[i];
37 i++;
38 j++;
39 if (i >= m) {
40 System.out.println("Matching index found at: " + (j - i + 1));
41 i = kmpNext[i];
42 }
43 }
44 }
字符串与模式匹配算法(三):KMP算法的更多相关文章
- 字符串匹配算法(三)-KMP算法
今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Prat ...
- 字符串匹配算法之 kmp算法 (python版)
字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...
- 字符串的模式匹配算法——KMP模式匹配算法
朴素的模式匹配算法(C++) 朴素的模式匹配算法,暴力,容易理解 #include<iostream> using namespace std; int main() { string m ...
- 模式串匹配之KMP算法
模式串匹配之KMP算法 KMP算法 模式值计算(next[j]) (1) next[0]=-1, 第一个字符模式值为-1 (2) next[j]=-1, T中下标为j的字符与首字符相同,且j前面的1 ...
- 常用算法3 - 字符串查找/模式匹配算法(BF & KMP算法)
相信我们都有在linux下查找文本内容的经历,比如当我们使用vim查找文本文件中的某个字或者某段话时,Linux很快做出反应并给出相应结果,特别方便快捷! 那么,我们有木有想过linux是如何在浩如烟 ...
- 字符串匹配算法之kmp算法
kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...
- 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!
前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...
- Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化
1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...
- 字符串与模式匹配算法(四):BM算法
一.BM算法介绍 BM算法(Boyer-Moore算法)是罗伯特·波义尔(Robert Boyer)和杰·摩尔(J·Moore)在1977年共同提出的.与KMP算法不同的是,BM算法是模式串P由左向右 ...
随机推荐
- 2.1Java基础
2.1.9面向对象的三大特性(携程): 封装:把一个对象的属性隐藏在对象内部,外部对象不能直接访问这个对象的内部信息.但是可以提供一些可以被外界访问的方法来操作属性.就比如我们常常创建一个类,把他的属 ...
- 学生信息管理系统.cpp(大二上)
#include<iostream> #include<fstream> #include<string> #include<iomanip> #i ...
- CodeForce-782B The Meeting Place Cannot Be Changed(高精度二分)
https://vjudge.net/problem/CodeForces-782B B. The Meeting Place Cannot Be Changed time limit per tes ...
- 关于Container容器以及IoC注入机制的认识
container 容器的概念: 1 container 是一个Java 所编写的程序,用于对象之间之间管理对象关系. 主要的java EE 容器如下: Java容器类包含List.ArrayList ...
- Rust之旅 02.通过例子学习自定义类型
本期文章接上期继续讲述Rust语言中的数据类型,Rust自定义数据类型主要是通过下面这两个关键字来创建: 结构体( struct ): 定义一个结构体(structure) 枚举( enum ): 定 ...
- 简单学习PHP中的层次性能分析器
在 PHP 中,我们需要进行调试的时候,一般都会使用 memory_get_usage() 看下内存的使用情况.但如果想看当前的脚本 CPU 的占用情况就没有什么现成的函数了.不过,PHP 也为我们提 ...
- 关于PHP的方法参数类型约束
在之前的文章PHP方法参数的那点事儿中,我们讲过关于PHP方法参数的一些小技巧.今天,我们带来的是更加深入的研究一下PHP中方法的参数类型. 在PHP5之后,PHP正式引入了方法参数类型约束.也就是如 ...
- DEDECMS首页循环调用一级栏目和二级栏目的实现方法
调用方法: {dede:channelartlist typeid='2'} <li class="First"><a href="{dede:fiel ...
- Docker系列(1) - Centos8.X安装Docker
环境准备 需要会Linux的基础 Centos8.x 使用Xshell连接远程服务器 环境查看 #系统内核是4.18以上 [root@localhost ~]# uname -r 4.18.0-305 ...
- php无限分类 构建树形结构
<?php class Classification { const PARENT_ID = 'parentid'; const ID = 'id'; const CHILDREN = 'chi ...