KMP算法-Java实现
目的:
为了解决字符串模式匹配
历程:
朴素模式匹配:逐次进行比较
KMP算法:利用匹配失败得到的信息,来最大限度的移动模式串,以此来减少比较次数提高性能
概念:
m:是目标串长度
n:是模式串长度
j:某次匹配时,第一次出现的不同的索引位置(有的称为:失配位)
k:最长首尾串长度(有的称为:最长公共前后缀)
核心思想:
S S0 S1 ...... 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实现的更多相关文章
- KMP算法java实现
/** * 假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置 如果j = -1,或者当前字符匹配成功(即S[i] == * P[j]),都令i++,j++,继续匹配下一个字符: 如果j != ...
- 经典KMP算法C++与Java实现代码
前言: KMP算法是一种字符串匹配算法,由Knuth,Morris和Pratt同时发现(简称KMP算法).KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.比 ...
- 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现
1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...
- Java实现KMP算法
/** * Java实现KMP算法 * * 思想:每当一趟匹配过程中出现字符比较不等,不需要回溯i指针, * 而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远 * 的一段 ...
- [转]KMP算法理解及java实现
这大概是我看的最好懂的KMP算法讲解了,不过我还只弄懂了大概思想,算法实现我到时候用java实现一遍 出处:知乎 https://www.zhihu.com/question/21923021/ans ...
- KMP算法中next数组的理解与算法的实现(java语言)
KMP 算法我们有写好的函数帮我们计算 Next 数组的值和 Nextval 数组的值,但是如果是考试,那就只能自己来手算这两个数组了,这里分享一下我的计算方法吧. 计算前缀 Next[i] 的值: ...
- 算法(Java实现)—— KMP算法
KMP算法 应用场景 字符串匹配问题 有一个字符串str1 = " hello hello llo hhello lloh helo" 一个子串str2 = "hello ...
- Java数据结构之字符串模式匹配算法---KMP算法2
直接接上篇上代码: //KMP算法 public class KMP { // 获取next数组的方法,根据给定的字符串求 public static int[] getNext(String sub ...
- Java数据结构之字符串模式匹配算法---KMP算法
本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基 ...
随机推荐
- JVM系列-分代收集垃圾回收
Java自动垃圾回收(Automatic Garbage Collection)是自动回收堆上不再使用的内存,new的对象在程序中没有引用指向它,就会被回收.回收的实现很多,有Reference Co ...
- fc-san
在SAN网络中,所有的数据传输在高速.高带宽的网络中进行,SAN存储实现的是直接对物理硬件的块级存储访问,提高了存储的性能和升级能力. 早期的SAN采用的是光纤通道(FC,Fibre Channel) ...
- iOS-网络基础
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- 分区函数Partition By的与row_number()的用法以及与排序rank()的用法详解(获取分组(分区)中前几条记录)
partition by关键字是分析性函数的一部分,它和聚合函数不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录,partition by用于给结果集分组,如果没有指 ...
- ExtJs4之TreePanel
Tree介绍 树形结构,是程序开发,不可缺少的组件之一.ExtJs中的树,功能强大美观实用.功能齐全,拖拉,排序,异步加载等等. 在ExtJs4中Tree和Grid具有相同的父类,因此Grid具有的特 ...
- 【Win10应用开发】自适应磁贴中的分组
老周在上一篇文章中介绍过了自适应磁贴的基本结构,以及给大家演示了一些例子. 本文老周给大伙伴们说说自适应磁贴的另一个特点——分组呈现. 当磁贴的内容被分组后,每个组中的内容就会被视为一个整体.比如某磁 ...
- 【Win10 应用开发】解决VS 2015 RC不能调试手机应用的问题
VS2015 RC已发布,当然这个版本还不能用于实际生产中,如果你没有测试环境,就等正式版出来,RC都来了,RTM就不远了. 如果你也像老周一样,已经在耍RC版了,你可能会遇到下面问题: 安装Win ...
- 传智播客--WPF基础视频学习--sender解释(小白内容)
sender是激发该事件的对象,如果用在Button的双击点击事件上的话,就是只当前点击的对象 用例子来说明一下,有两个Button控件,分别为1和2,同时绑定一个Button_Click事件 pri ...
- SubSonic3.0.0.4.2源码包与调用Dll
================================================================ 名 称:SubSonic插件版 本:3.0.0.4.2最后 ...
- csapp2e-chapter2-homework
一 前言 看了csapp2e第二章,感觉讲的很透彻,理解了一些以前学组成原理没有学懂的东西.这章最让我感觉深刻的还是计算机是怎么实现c语言中的基本数据类型的表示和操作的,这对程序员理解程序无疑是帮助巨 ...