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)的时间数量级上完成串的模式匹配操作,其基 ...
随机推荐
- 初学者--bootstrap(五)JavaScript插件(上)----在路上(6)
jQuery 插件为 Bootstrap 的组件赋予了“生命”.可以简单地一次性引入所有插件,或者逐个引入到你的页面中. 一:首先要确认的是,单个还是全部引入: JavaScript 插件可以单个引入 ...
- fir.im Weekly - 关于 Log Guru 开源、Xcode 探索和 Android7.0 适配
本期 fir.im Weekly 整理了最近的一些技术分享,包括关于 Log Guru 开源.Xcode 探索. Android7.0 适配等等 iOS/Android 相关的工具.源码分享和技术文章 ...
- Linux中grep搜索用法
有测试文件test.txt一枚,内容如下 aaabbbcccAAADDDEEEabcsdfjasldjfbcdokmABC 一.基本搜索常用1.现在想把abc okm筛选出来 grep "a ...
- HTML的页面IE注释
我们常常会在网页的HTML里面看到形如[if lte IE 9]……[endif]的代码,表示的是限定某些浏览器版本才能执行的语句,那么这些判断语句的规则是什么呢?请看下文: <!--[if ! ...
- CSS系列:CSS中盒子模型
盒子模型是CSS控制页面时一个很重要的概念.所有页面中的元素都可以看成是一个盒子,占据着一定的页面空间.可以通过调整盒子的边框和距离等参数,来调节盒子的位置和大小. 1. 盒子的内部结构 在CSS中, ...
- WPF MVVM框架下,VM界面写控件
MVVM正常就是在View页面写样式,ViewModel页面写逻辑,但是有的时候纯在View页面写样式并不能满足需求.我最近的这个项目就遇到了,因此只能在VM页面去写样式控件,然后绑定到View页面. ...
- 【原创】开源Math.NET基础数学类库使用(01)综合介绍
本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新 开源Math.NET基础数学类库使用总目录:[目录]开源Math.NET基础数学类库使用总目录 前言 ...
- AngularJs 动态加载模块和依赖
最近项目比较忙额,白天要上班,晚上回来还需要做Angular知识点的ppt给同事,毕竟年底要辞职了,项目的后续开发还是需要有人接手的,所以就占用了晚上学习的时间.本来一直不打算写这些第三方插件的学习笔 ...
- ES6 - Note5:Promise
1.Promise介绍 Promise最早是社区提出和实现,后面ES6将其写入标准,并原生提供Promise对象,是一种异步编程的解决方案,具体的概念大家可以去查看相关的资料.传统上处理异步都是以ca ...
- tn文本分析语言(三):高级语法
标签(空格分隔): 未分类 高级操作 1.脚本表达式 用双引号包含的脚本被称为脚本表达式,目前支持嵌入Python. 脚本表达式只能在顺序表达式中使用.代码可以在三个位置存在: |位置|功能|例子| ...