前言:

  KMP算法是一种字符串匹配算法,由Knuth,Morris和Pratt同时发现(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。比较流行的做法是实现一个next()函数,函数本身包含了模式串的局部匹配信息。由于next函数理解起来不太容易,本文同样是基于空间换时间的做法,但将采用另一种代码实现,希望可以更方便读者理解!

测试数据

aseeesatba   esat
as330kdwejjl_8   jjl_
faw4etoesting tio
aabacb abac

测试结果

4
9
-1
0

(注:若匹配则返回text子串的起始index;否则返回-1)

1.暴力查找的实现一

 1 // 暴力子串查找一式:O(M*N)
 2     private static int search0(String text, String pat) {
 3         int i, j, N = text.length(), M = pat.length();
 4         for (i = 0; i <= N - M; i++) {
 5             for (j = 0; j < M; j++) {
 6                 if (text.charAt(i + j) != pat.charAt(j))
 7                     break;
 8             }
 9             if (M == j)
10                 return i;
11         }
12         return -1;
13     }

    函数传入文本text和模式串pat,其中i和i+j分别标记text子串的首尾。若text存在子串匹配pat,则返回text子串起始index;否则返回-1;时间复杂度:O(M*N)

2.暴力查找实现二

 1 // 暴力子串查找二式:O(M*N)
 2     public static int search(String text, String pat) {
 3         int i, j;
 4         int N = text.length(), M = pat.length();
 5         for (i = 0, j = 0; i < N && j < M; i++) {
 6             if (text.charAt(i) == pat.charAt(j))
 7                 j++;
 8             else {
 9                 i -= j;
10                 j = 0;
11             }
12         }
13         return (j == M) ? (i - M) : -1;
14     }

    同样的一种暴力查找算法,通过不断的回溯文本串中的“i”进行判断。若text存在子串匹配pat,则返回text子串起始index;否则返回-1;时间复杂度:O(M*N)

3.KMP算法(空间换时间)

    为了优化算法时间复杂度,我们尝试进行一些信息存储,引入了额外的空间存储 dfa[][]。

    从上述第二种暴力查找算法中,我们可以得到启发。即,通过记录“j”保证“i”只能往右移动,无需往左回退。其中,dfa[i][j]

表示文本串中当前字符‘charAt(i)’时,下个文本字符'charAt(i+1)'应该与模式串匹配的位置(0~j)。

    这里我们引入有穷自动机DFA对dfa[][]进行数值的初始化。以模式串“aabacb”为例,匹配pat的DFA状态图如下:

    对应的代码如下:

1         //构造dfa[][]
2         dfa[pat.charAt(0)][0] = 1;
3         for(int X=0,j=0;j<M;j++){
4             for(int c=0;c<R;c++){
5                 dfa[c][j] = dfa[c][X];
6             }
7             dfa[pat.charAt(j)][j] = j+1;
8             X = dfa[pat.charAt(j)][X];
9         }

    其中,“X”表示不同的dfa状态,上述代码构造dfa[][]的时间复杂度为:O(N*R);

------------------------------------------------

Java完整代码

 1 package ch05.string.substring;
 2
 3 import java.io.File;
 4 import java.util.Scanner;
 5
 6 public class KMP {
 7
 8     private int R = 255;
 9     private String pat;
10     private int[][] dfa;
11
12     public KMP(String pat) {
13         this.pat = pat;
14         int M = pat.length();
15         dfa = new int[R][M];
16
17         //构造dfa[][]
18         dfa[pat.charAt(0)][0] = 1;
19         for(int X=0,j=0;j<M;j++){
20             for(int c=0;c<R;c++){
21                 dfa[c][j] = dfa[c][X];
22             }
23             dfa[pat.charAt(j)][j] = j+1;
24             X = dfa[pat.charAt(j)][X];
25         }
26
27     }
28
29     public int search(String text){
30         int i,j;
31         int N = text.length(),M = pat.length();
32         for(i=0,j=0;i<N && j<M; i++){
33             j = dfa[text.charAt(i)][j];
34         }
35         return j==M?(i-M):-1;
36     }
37
38     public static void main(String[] args) throws Exception {
39         //从文件读入数据
40         Scanner input = new Scanner(new File("datain.txt"));
41         while(input.hasNext()){
42             String text = input.next();
43             KMP kmp = new KMP(input.next());
44             int ans = kmp.search(text);
45             //输出答案
46             System.out.println(ans);
47         }
48     }
49 }

------------------------------------------------

C/C++完整代码  

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<string>
 5 using namespace std;
 6 const int maxn=1e4+10;
 7 const int R=256;
 8 int dfa[R][maxn];
 9
10 string text,pat;
11 void init(){
12     int M=pat.length();
13     dfa[pat[0]][0] = 1;
14     for(int X=0,j=1;j<M;j++){
15         /**直接从dfa[][X]复制到dfa[][j]*/
16         for(int c=0;c<R;c++){
17             dfa[c][j] = dfa[c][X];
18         }
19         /**匹配到,继续往右走*/
20         dfa[pat[j]][j] = j+1;
21         X = dfa[pat[j]][X];
22     }
23
24 }
25 int search1(){
26     init();
27     int i,j,N = text.length(),M = pat.length();
28     for(i=0,j=0;i<N && j<M;i++){
29         j = dfa[text[i]][j];
30     }
31     return j==M?(i-M):-1;
32 }
33 int main(){
34     freopen("datain.txt","r",stdin);
35     while(cin>>text>>pat){
36         cout<<search1()<<endl;
37     }
38     return 0;
39 }

Reference:

  【1】Algorithms(4th) -谢路云

【2】http://baike.baidu.com/link?url=_WLufLz1lw2e4eMgU6DI8IblUkp838Qf595Nqxfg2JN3aqNED2FFe3U6J9yPmUv_zKfFqAAQJid7Gzho3ork8K

转载于:https://www.cnblogs.com/SeaSky0606/p/4925755.html

经典KMP算法C++与Java实现代码相关推荐

  1. 十大经典排序算法详细总结 图形展示 代码示例

    文章目录 十大经典排序算法详细总结 0.排序算法说明 1.冒泡排序(Bubble Sort) 2.选择排序(Selection Sort) 3.插入排序(Insertion Sort) 4.希尔排序( ...

  2. java string逆序_java经典入门算法题,java初学者必备

    java经典入门算法题 开头求关注警告 喜欢这样文章的可以关注我,我会持续更新,你们的关注是我更新的动力!需要更多java学习资 料的也可以私信我! 祝关注我的人都:身体健康,财源广进,福如东海,寿比 ...

  3. KMP算法详解:使用部分匹配表PMT来理解KMP算法,使用Java实现

    有些算法,适合从它产生的动机,如何设计与解决问题这样正向地去介绍.但KMP算法真的不适合这样去学.最好的办法是先搞清楚它所用的数据结构是什么,再搞清楚怎么用,最后为什么的问题就会有恍然大悟的感觉.我试 ...

  4. LeetCode第28题 实现strStr()之KMP算法(C++)【代码已提交成功】

    目录 初步思路 朴素匹配算法 KMP算法 NEXT数组 利用NEXT数组改进朴素匹配算法 初步思路 这是一道难度为简单的题,所以不熟悉的话可能第一反应就是朴素匹配的算法.但因为考研的时候学过数据结构, ...

  5. KMP算法理解(超简洁-易懂代码)

    文章目录 KMP算法 1. 暴力做法是怎么做的 1.1 时间复杂度: O(n^2) 2. 怎么去优化它 2.1 一般情况: 2.2 原理: 2.3 匹配过程 2.4 kmp 匹配的实现代码 2.5 n ...

  6. 买什么数据结构与算法,这里有:动态图解十大经典排序算法(含JAVA代码实现)

    上篇的动图数据结构反响不错,这次来个动图排序算法大全.数据结构与算法,齐了. 几张动态图捋清Java常用数据结构及其设计原理 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: ...

  7. java array 元素的位置_数据结构与算法:动态图解十大经典排序算法(含JAVA代码实现)...

    点击上方"JAVA",星标公众号 重磅干货,第一时间送达 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: 冒泡排序 选择排序 插入排序 希尔排序 归并排 ...

  8. 十大经典排序算法之堆排序(Java代码实现)

    算法原理 堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近视完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点.堆排序可以说 ...

  9. (四)十大经典排序算法(动画图解,代码完全)

    排序算法是<数据结构与算法>中最基本的算法之一 1. 冒泡排序 1.1 算法步骤 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的 ...

最新文章

  1. idea使用maven创建java工程log4j的配置
  2. ***快速理解Docker - 容器级虚拟化解决方案
  3. BZOJ 1137 半平面交
  4. Kubernetes从懵圈到熟练:读懂这一篇,集群节点不下线
  5. 神经网络快速搭建之一站式访问
  6. apicloud入门学习笔记1:简单介绍
  7. python将空格变成换行_Python基础之PEP8规范(代码写作规范)
  8. Java 1.1字符串
  9. 阿里云边缘计算三年,都为开发者带来了什么?
  10. 点击button后改变文字_24. 教你零基础搭建小程序:小程序的常见组件(5)— button标签...
  11. 如何用Eclipse进行单元测试
  12. 计算机无法装补丁,老司机教你win7 sp1补丁安装失败怎么办
  13. 用c语言输出英文字母表音标,26个英文字母表中文
  14. DRM dumb,prime介绍
  15. hiddenlayer安装
  16. 苹果关闭 iOS 14.4.2 系统验证通道
  17. mp4转换m3u8格式php,【过程】第一次将m3u8文件转换为MP4文件经验分享
  18. 扫描文档SDK ocr识别技术
  19. 80端口跟8080端口有什么具体区别?
  20. 一道积分不等式的最优估计探索

热门文章

  1. 将本地docker镜像推送到阿里云镜像仓库
  2. 【完整代码】使用Semaphore实现线程的交替执行打印 A1B2C3D4E5
  3. Apollo配置发布原理
  4. MATLAB中改变默认当前文件夹
  5. 没有shell63号单元_苏教版15年级数学上册第七单元整理与复习+同步练习
  6. jenkins中Git Parameter Plugin使用
  7. toArray()方法使用说明
  8. Markdown公式输入(very nice!!!)
  9. php过滤第一个逗号和最后一个逗号,PHP字符过滤函数去除字符串最后一个逗号(rtrim)...
  10. ESP32又有新玩法了,启明云端把它带入到冷门行业--测试治具