前言:

  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.暴力查找的实现一

 // 暴力子串查找一式:O(M*N)
private static int search0(String text, String pat) {
int i, j, N = text.length(), M = pat.length();
for (i = 0; i <= N - M; i++) {
for (j = 0; j < M; j++) {
if (text.charAt(i + j) != pat.charAt(j))
break;
}
if (M == j)
return i;
}
return -1;
}

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

2.暴力查找实现二

 // 暴力子串查找二式:O(M*N)
public static int search(String text, String pat) {
int i, j;
int N = text.length(), M = pat.length();
for (i = 0, j = 0; i < N && j < M; i++) {
if (text.charAt(i) == pat.charAt(j))
j++;
else {
i -= j;
j = 0;
}
}
return (j == M) ? (i - M) : -1;
}

    同样的一种暴力查找算法,通过不断的回溯文本串中的“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状态图如下:

    对应的代码如下:

         //构造dfa[][]
dfa[pat.charAt(0)][0] = 1;
for(int X=0,j=0;j<M;j++){
for(int c=0;c<R;c++){
dfa[c][j] = dfa[c][X];
}
dfa[pat.charAt(j)][j] = j+1;
X = dfa[pat.charAt(j)][X];
}

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

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

Java完整代码

 package ch05.string.substring;

 import java.io.File;
import java.util.Scanner; public class KMP { private int R = 255;
private String pat;
private int[][] dfa; public KMP(String pat) {
this.pat = pat;
int M = pat.length();
dfa = new int[R][M]; //构造dfa[][]
dfa[pat.charAt(0)][0] = 1;
for(int X=0,j=0;j<M;j++){
for(int c=0;c<R;c++){
dfa[c][j] = dfa[c][X];
}
dfa[pat.charAt(j)][j] = j+1;
X = dfa[pat.charAt(j)][X];
} } public int search(String text){
int i,j;
int N = text.length(),M = pat.length();
for(i=0,j=0;i<N && j<M; i++){
j = dfa[text.charAt(i)][j];
}
return j==M?(i-M):-1;
} public static void main(String[] args) throws Exception {
//从文件读入数据
Scanner input = new Scanner(new File("datain.txt"));
while(input.hasNext()){
String text = input.next();
KMP kmp = new KMP(input.next());
int ans = kmp.search(text);
//输出答案
System.out.println(ans);
}
}
}

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

C/C++完整代码  

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
const int maxn=1e4+;
const int R=;
int dfa[R][maxn]; string text,pat;
void init(){
int M=pat.length();
dfa[pat[]][] = ;
for(int X=,j=;j<M;j++){
/**直接从dfa[][X]复制到dfa[][j]*/
for(int c=;c<R;c++){
dfa[c][j] = dfa[c][X];
}
/**匹配到,继续往右走*/
dfa[pat[j]][j] = j+;
X = dfa[pat[j]][X];
} }
int search1(){
init();
int i,j,N = text.length(),M = pat.length();
for(i=,j=;i<N && j<M;i++){
j = dfa[text[i]][j];
}
return j==M?(i-M):-;
}
int main(){
freopen("datain.txt","r",stdin);
while(cin>>text>>pat){
cout<<search1()<<endl;
}
return ;
}

Reference:

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

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

经典KMP算法C++与Java实现代码的更多相关文章

  1. 数据结构与算法JavaScript (五) 串(经典KMP算法)

    KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配 ...

  2. [转]KMP算法理解及java实现

    这大概是我看的最好懂的KMP算法讲解了,不过我还只弄懂了大概思想,算法实现我到时候用java实现一遍 出处:知乎 https://www.zhihu.com/question/21923021/ans ...

  3. poj 3461 - Oulipo 经典kmp算法问题

    2017-08-13 19:31:47 writer:pprp 对kmp算法有了大概的了解以后,虽然还不够深入,但是已经可以写出来代码,(可以说是背会了) 所以这道题就作为一个模板,为大家使用吧. 题 ...

  4. 动画展现十大经典排序算法(附Java代码)

    0.算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序: ...

  5. 【字符串处理】关于KMP算法输出的是什么&代码

    输入: ABCDABTBD_TISABCDABCABCDABC q为当前nxt处理的模版文本串下标: k为“失配时去哪里”,详情请看注释. --------------我是求完nxt的分界线----- ...

  6. 几个比较经典的算法问题的java实现

    1.八皇后问题 public class EightQueen { private static final int ROW = 16; private static final int COL = ...

  7. 一文搞定十大经典排序算法(Java实现)

    本文总结十大经典排序算法及变形,并提供Java实现. 参考文章: 十大经典排序算法总结(Java语言实现) 快速排序算法—左右指针法,挖坑法,前后指针法,递归和非递归 快速排序及优化(三路划分等) 一 ...

  8. 70. Implement strStr() 与 KMP算法

    Implement strStr() Implement strStr(). Returns a pointer to the first occurrence of needle in haysta ...

  9. KMP算法浅析

    具体参见: KMP算法详解 背景: KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字.其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除 ...

随机推荐

  1. IOS开发基础知识--碎片28

    1:通用的weakify和strongify /** * 强弱引用转换,用于解决代码块(block)与强引用self之间的循环引用问题 * 调用方式: `@weakify_self`实现弱引用转换,` ...

  2. Web客户端数据存储学习笔记——Cookie

    今天对登录访问的安全以及web客户端存储做了一些大致的学习,决定在这方面加深理解,记录在博客里.第一个接触到的是Cookie... WHAT? WHY? HOW? 在学习cookie的使用时发现其名称 ...

  3. RHEL 6.6安装桌面环境GNOME

    在测试服务器(Red Hat Enterprise Linux Server release 6.6)需要安装桌面系统环境,于是选择GNOME桌面环境安装. 一:检查系统的运行级别以及是否安装了桌面环 ...

  4. Linux如何找出用户的创建时间

    在Linux系统中,如何找到用户创建的时间呢? 其实是没有标准方法查找用户创建时间.下面再搜索了一些资料后,自己验证并测试了一下这些方法,仅供参考: 1:如果创建的用户有家目录,那么可以ls -l / ...

  5. FFmpeg编译找不到库文件

    在编译FFmpeg的时候,用./configure 进行配置,经常会出现找不到库文件的情况,原因大概就两个: 1.没有安装库文件或者安装的库文件版本不对 2.FFmpeg没有找到库文件 前者的问题好解 ...

  6. ARM汇编程序结构

    ARM汇编程序结构 一个ARM程序可以被划分为多个代码段和数据段,在汇编的时候这些段会被形成一个可执行文件 .text ;正文段,包含程序的指令代码 .data ;数据段,包含固定的数据,如常量,字符 ...

  7. Windows 设置Mongodb

    安装MongoDB 将解压所得的bin文件夹内文件部署于C:\mongodb\bin 建立数据库文件夹 C:\mongodb\data\db 准备以下内容的配置文件mongodb.cfg dbpath ...

  8. 安装 Visual Studio Web Tools 的奇怪问题

    安装Microsoft ASP.NET 5 RC 1 时提示 0x80070005 - 拒绝访问 日志文件为 [1968:3F64][2015-11-20T10:08:36]i010: Launchi ...

  9. mysql常用基本操作

    mysql常用操作 查看都有哪些库 show databases; 查看某个库的表 use 库名; show tables; 查看表的字段 desc 表名; 当前是哪个用户 select user() ...

  10. Leetcode: word search

    July 6, 2015 Problem statement: Word Search Given a 2D board and a word, find if the word exists in ...