目的:

为了解决字符串模式匹配

历程:

朴素模式匹配:逐次进行比较

KMP算法:利用匹配失败得到的信息,来最大限度的移动模式串,以此来减少比较次数提高性能

概念:

m:是目标串长度

n:是模式串长度

j:某次匹配时,第一次出现的不同的索引位置(有的称为:失配位

k:最长首尾串长度(有的称为:最长公共前后缀

核心思想:

S   S0 S...... Si-j-1 Si-j Si-j+1 Si-j+2 ...... Si-2 Si-1 Si ...... Sn-1

||     ||      ||            ||   ||   ×

P                            P0    P1      P2              Pj-2 Pj-1 Pj

有Si-j-1Si-jSi-j+1 Si-j+2 ...... Si-2 Si-1=P0P1 P2 ...... Pj-2 Pj-1

如果  P0P1 P2 ...... Pj-2 ≠ P1 P2 ...... Pj-2Pj-1

则可以立即断定 P0P1 P2 ...... Pj-2 ≠ Si-j+1 Si-j+2 ...... Si-2 Si-1,即:朴素模式匹配的下一次移动一定不匹配,则可以跳过这一次

如果  P0P1 P2 ...... Pj-3 ≠ P2 ...... Pj-2Pj-1

则可以立即断定 P0P1 P2 ...... Pj-2 ≠ Si-j+1 Si-j+2 ...... Si-2 Si-1,即:朴素模式匹配的下一次移动一定不匹配,则可以跳过这一次

直到第一次出现相等的情况终止:P0P1 P2 ...... Pk-1 = Pj-k ...... Pj-2Pj-1

得到的k就是最长的首尾串长度,然后通过 j-k 得到了我们需要移动的位数,这样我们就利用了匹配失败的结果,得到了我们可以移动的步数,提升了性能

关于k:

其实肉眼就直接能看出来,k是最长首尾串长度,比如:

11111 k=4(前缀:1111,后缀:1111)

12112 k=2(前缀:12,后缀:12)

12345 k=0(无相同前缀后缀)

例子:

S=ababababababb

P=abababb

重申一下原理:朴素模式匹配效率低的原因是一位一位的比较,丢弃了之前失败的信息。而KMP算法从匹配失败的信息中得到可以最大移动的步数,以此来减少比较的次数,来提升性能。

这里并没有提及,next数组及newnext数组,模式串的特征向量N,其实不用管它,思想理解了,只是别人起了个叫法而已。

Java代码:

    /**
* 朴素模式匹配
*
* @param source 目标串
* @param pattern 模式串
*/
private static void plain(String source, String pattern) {
int res=0;
int sourceLength=source.length();
int patternLength=pattern.length();
for(int i=0;i<=(sourceLength-patternLength);i++){
res++;
String str=source.substring(i, i+patternLength);
if(str.equals(pattern)){
p("朴素模式:匹配成功");
break;
}
}
p("朴素模式:一共匹配"+res+"次数");
}
    //KMP算法实现
   private static void KMP(String source, String pattern) {
int[] N=getN(pattern);
int res=0;
int sourceLength=source.length();
int patternLength=pattern.length();
for(int i=0;i<=(sourceLength-patternLength);){
res++;
String str=source.substring(i, i+patternLength);//要比较的字符串
p(str);
int count=getNext(pattern, str,N);
p("移动"+count+"步");
if(count==0){
p("KMP:匹配成功");
break;
}
i=i+count;
}
p("KMP:一共匹配"+res+"次数");
}
/**
* 得到下一次要移动的次数
*
* @param pattern
* @param str
* @param N
* @return 0,字符串匹配;
*/
private static int getNext(String pattern,String str,int[] N) {
int n = pattern.length();
char v1[] = str.toCharArray();
char v2[] = pattern.toCharArray();
int x = 0;
while (n-- != 0) {
if (v1[x] != v2[x]){
if(x==0){
return 1;//如果第一个不相同,移动1步
}
return x-N[x-1];//x:第一次出现不同的索引的位置,即j
}
x++;
}
return 0;
}
private static int[] getN(String pattern) {
char[] pat=pattern.toCharArray();
int j=pattern.length()-1;
int[] N=new int[j+1];
for(int i=j;i>=2;i--){
N[i-1]=getK(i,pat);
}
for(int a:N)
p(a);
return N;
}
private static int getK(int j, char[] pat) {
int x=j-2;
int y=1;
while (x>=0 && compare(pat, 0, x, y, j-1)) {
x--;
y++;
}
return x+1;
}
private static boolean compare(char[] pat,int b1,int e1,int b2,int e2){
int n = e1-b1+1;
while (n-- != 0) {
if (pat[b1] != pat[b2]){
return true;
}
b1++;
b2++;
}
return false;
}
public static void p(Object obj) {
System.out.println(obj);
}

next数组:

KMP能提高性能原因是减少了比较次数,也就是知道k

而k从只和j有关,这就意味着移动的次数只和模式串有关,和目标串无关

简单来说,就是我们得到模式串后就能立马知道移动的次数,这就是next数组。里面储存的就是k值。

KMP算法-Java实现的更多相关文章

  1. KMP算法java实现

    /** * 假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置 如果j = -1,或者当前字符匹配成功(即S[i] == * P[j]),都令i++,j++,继续匹配下一个字符: 如果j != ...

  2. 经典KMP算法C++与Java实现代码

    前言: KMP算法是一种字符串匹配算法,由Knuth,Morris和Pratt同时发现(简称KMP算法).KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.比 ...

  3. 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现

    1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...

  4. Java实现KMP算法

    /**  * Java实现KMP算法  *   * 思想:每当一趟匹配过程中出现字符比较不等,不需要回溯i指针,   * 而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远   * 的一段 ...

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

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

  6. KMP算法中next数组的理解与算法的实现(java语言)

    KMP 算法我们有写好的函数帮我们计算 Next 数组的值和 Nextval 数组的值,但是如果是考试,那就只能自己来手算这两个数组了,这里分享一下我的计算方法吧. 计算前缀 Next[i] 的值: ...

  7. 算法(Java实现)—— KMP算法

    KMP算法 应用场景 字符串匹配问题 有一个字符串str1 = " hello hello llo hhello lloh helo" 一个子串str2 = "hello ...

  8. Java数据结构之字符串模式匹配算法---KMP算法2

    直接接上篇上代码: //KMP算法 public class KMP { // 获取next数组的方法,根据给定的字符串求 public static int[] getNext(String sub ...

  9. Java数据结构之字符串模式匹配算法---KMP算法

    本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基 ...

随机推荐

  1. JVM系列-分代收集垃圾回收

    Java自动垃圾回收(Automatic Garbage Collection)是自动回收堆上不再使用的内存,new的对象在程序中没有引用指向它,就会被回收.回收的实现很多,有Reference Co ...

  2. fc-san

    在SAN网络中,所有的数据传输在高速.高带宽的网络中进行,SAN存储实现的是直接对物理硬件的块级存储访问,提高了存储的性能和升级能力. 早期的SAN采用的是光纤通道(FC,Fibre Channel) ...

  3. iOS-网络基础

    概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...

  4. 分区函数Partition By的与row_number()的用法以及与排序rank()的用法详解(获取分组(分区)中前几条记录)

    partition by关键字是分析性函数的一部分,它和聚合函数不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录,partition by用于给结果集分组,如果没有指 ...

  5. ExtJs4之TreePanel

    Tree介绍 树形结构,是程序开发,不可缺少的组件之一.ExtJs中的树,功能强大美观实用.功能齐全,拖拉,排序,异步加载等等. 在ExtJs4中Tree和Grid具有相同的父类,因此Grid具有的特 ...

  6. 【Win10应用开发】自适应磁贴中的分组

    老周在上一篇文章中介绍过了自适应磁贴的基本结构,以及给大家演示了一些例子. 本文老周给大伙伴们说说自适应磁贴的另一个特点——分组呈现. 当磁贴的内容被分组后,每个组中的内容就会被视为一个整体.比如某磁 ...

  7. 【Win10 应用开发】解决VS 2015 RC不能调试手机应用的问题

    VS2015 RC已发布,当然这个版本还不能用于实际生产中,如果你没有测试环境,就等正式版出来,RC都来了,RTM就不远了. 如果你也像老周一样,已经在耍RC版了,你可能会遇到下面问题: 安装Win ...

  8. 传智播客--WPF基础视频学习--sender解释(小白内容)

    sender是激发该事件的对象,如果用在Button的双击点击事件上的话,就是只当前点击的对象 用例子来说明一下,有两个Button控件,分别为1和2,同时绑定一个Button_Click事件 pri ...

  9. SubSonic3.0.0.4.2源码包与调用Dll

    ================================================================ 名    称:SubSonic插件版    本:3.0.0.4.2最后 ...

  10. csapp2e-chapter2-homework

    一 前言 看了csapp2e第二章,感觉讲的很透彻,理解了一些以前学组成原理没有学懂的东西.这章最让我感觉深刻的还是计算机是怎么实现c语言中的基本数据类型的表示和操作的,这对程序员理解程序无疑是帮助巨 ...