经典KMP算法C++与Java实现代码
前言:
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实现代码相关推荐
- 十大经典排序算法详细总结 图形展示 代码示例
文章目录 十大经典排序算法详细总结 0.排序算法说明 1.冒泡排序(Bubble Sort) 2.选择排序(Selection Sort) 3.插入排序(Insertion Sort) 4.希尔排序( ...
- java string逆序_java经典入门算法题,java初学者必备
java经典入门算法题 开头求关注警告 喜欢这样文章的可以关注我,我会持续更新,你们的关注是我更新的动力!需要更多java学习资 料的也可以私信我! 祝关注我的人都:身体健康,财源广进,福如东海,寿比 ...
- KMP算法详解:使用部分匹配表PMT来理解KMP算法,使用Java实现
有些算法,适合从它产生的动机,如何设计与解决问题这样正向地去介绍.但KMP算法真的不适合这样去学.最好的办法是先搞清楚它所用的数据结构是什么,再搞清楚怎么用,最后为什么的问题就会有恍然大悟的感觉.我试 ...
- LeetCode第28题 实现strStr()之KMP算法(C++)【代码已提交成功】
目录 初步思路 朴素匹配算法 KMP算法 NEXT数组 利用NEXT数组改进朴素匹配算法 初步思路 这是一道难度为简单的题,所以不熟悉的话可能第一反应就是朴素匹配的算法.但因为考研的时候学过数据结构, ...
- KMP算法理解(超简洁-易懂代码)
文章目录 KMP算法 1. 暴力做法是怎么做的 1.1 时间复杂度: O(n^2) 2. 怎么去优化它 2.1 一般情况: 2.2 原理: 2.3 匹配过程 2.4 kmp 匹配的实现代码 2.5 n ...
- 买什么数据结构与算法,这里有:动态图解十大经典排序算法(含JAVA代码实现)
上篇的动图数据结构反响不错,这次来个动图排序算法大全.数据结构与算法,齐了. 几张动态图捋清Java常用数据结构及其设计原理 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: ...
- java array 元素的位置_数据结构与算法:动态图解十大经典排序算法(含JAVA代码实现)...
点击上方"JAVA",星标公众号 重磅干货,第一时间送达 本文将采取动态图+文字描述+正确的java代码实现来讲解以下十大排序算法: 冒泡排序 选择排序 插入排序 希尔排序 归并排 ...
- 十大经典排序算法之堆排序(Java代码实现)
算法原理 堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法.堆积是一个近视完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点.堆排序可以说 ...
- (四)十大经典排序算法(动画图解,代码完全)
排序算法是<数据结构与算法>中最基本的算法之一 1. 冒泡排序 1.1 算法步骤 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的 ...
最新文章
- idea使用maven创建java工程log4j的配置
- ***快速理解Docker - 容器级虚拟化解决方案
- BZOJ 1137 半平面交
- Kubernetes从懵圈到熟练:读懂这一篇,集群节点不下线
- 神经网络快速搭建之一站式访问
- apicloud入门学习笔记1:简单介绍
- python将空格变成换行_Python基础之PEP8规范(代码写作规范)
- Java 1.1字符串
- 阿里云边缘计算三年,都为开发者带来了什么?
- 点击button后改变文字_24. 教你零基础搭建小程序:小程序的常见组件(5)— button标签...
- 如何用Eclipse进行单元测试
- 计算机无法装补丁,老司机教你win7 sp1补丁安装失败怎么办
- 用c语言输出英文字母表音标,26个英文字母表中文
- DRM dumb,prime介绍
- hiddenlayer安装
- 苹果关闭 iOS 14.4.2 系统验证通道
- mp4转换m3u8格式php,【过程】第一次将m3u8文件转换为MP4文件经验分享
- 扫描文档SDK ocr识别技术
- 80端口跟8080端口有什么具体区别?
- 一道积分不等式的最优估计探索
热门文章
- 将本地docker镜像推送到阿里云镜像仓库
- 【完整代码】使用Semaphore实现线程的交替执行打印 A1B2C3D4E5
- Apollo配置发布原理
- MATLAB中改变默认当前文件夹
- 没有shell63号单元_苏教版15年级数学上册第七单元整理与复习+同步练习
- jenkins中Git Parameter Plugin使用
- toArray()方法使用说明
- Markdown公式输入(very nice!!!)
- php过滤第一个逗号和最后一个逗号,PHP字符过滤函数去除字符串最后一个逗号(rtrim)...
- ESP32又有新玩法了,启明云端把它带入到冷门行业--测试治具