一、理解next数组

1、约定next[0]=-1,
同时可以假想在sub串的最前面有一个通配符“*”,能够任意匹配。对应实际的代码t<0时的处理情况。

2、next[j]可以有如下的几种理解思路:
1)next[j]为sub[j]前面的字符串的前后缀字符串匹配的最大匹配长度
例如sub=“ababap”
next[5]=3,前后追匹配字符串为“aba”
2)在sub[j]位置匹配失败后,next[j]为为sub串的位置指针j能够先前回溯到的位置。
3)next[j]为最长前缀匹配串的下一个字符位置(这就是为什么求next数组时需要有t=next[t]这一步。)

由此不难发现:
next[j]的值越大,在base[i]与sub[j]处匹配失败时,sub串的位置指针j需要回溯的跨越长度越小。
反之,
next[j]的值越小,在base[i]与sub[j]处匹配失败时,sub串的位置指针j需要回溯的跨越长度越大。
极端情况下,next[j]为0,sub串的位置指针j直接回溯到sub串起始位置。

二、理解KMP主算法

1、base串的位置指针i在匹配的过程中始终不会向前回溯,这也是KMP算法较蛮力匹配算法高效的原因。
2、当base[i]和sub[j]匹配失败时,sub串的位置指针j回溯,j变小,等效于将sub串向右移动。

j回溯到next[j]的位置。

三、理解改进的next数组

改进的next数组的取值优化算法:

if (sub.charAt(t) != sub.charAt(j)) {
next[j] = t;
}else{
next[j] = next[t];
}

考虑对于base主串和sub串如下:
String base = "aaaabcde";
String sub = "aaaaax";
用改进的next数组取值为[-1,-1,-1,-1,-1,4]
当b=base[4] != sub[4]=x时,j=next[j]=-1,直接跳到sub串的哨兵“*”位置,然后进入j<0,进而i++,j++,中间省略了层层回溯的步骤。

其原理相当于简化了将KMP主算法中的sub位置指针j的跳转条件t = next[t];的负担。
因为在KMP主算法中base[i] != sub[j]时,j经过第一次回溯之后,如果出现sub[[next[j]]]=sub[j]的话,不难推断sub[[next[j]]]=sub[j]!=base[i],那么这一次回溯是没有实际效果的,j必将还要向前回溯。。。基于这样的考虑,直接对next数组做优化处理,避免了主算法中这样的层层回溯,能够减少主算法中while循环的次数。

改进的next数组能够避免sub串的位置指针j层层向前回溯,保证每次j的回溯都是有效的。

四、java实现如下

 package agstring;

 public class KMP {
public static int[] getNextAry(String sub){
int subLenght = sub.length();
int[] next = new int[subLenght];
int t = next[0] = -1,j = 0;
while(j < subLenght-1){
if(t < 0 || sub.charAt(t) == sub.charAt(j)){
t++;
j++;
next[j] = t;//可优化
}else {
t = next[t];
}
}
return next;
}
public static int[] getNextAryExt(String sub){
int subLenght = sub.length();
int[] next = new int[subLenght];
int t = next[0] = -1,j = 0;
while(j < subLenght-1){
if(t < 0 || sub.charAt(t) == sub.charAt(j)){
t++;
j++;
next[j] = sub.charAt(t) != sub.charAt(j)?t:next[t];
}else {
t = next[t];
}
}
return next;
} /*
*i为主串位置指针,j为sub串位置指针
*j<0的情况为sub串的位置指针为0,且sub[0] != base[i]
*匹配能够成功的情况必为j==subLength
* */
public static int matchOfKMP(String base,String sub){
int baseLength = base.length();
int subLength = sub.length();
int i = 0,j = 0;
int[] next = getNextAryExt(sub);
while(i < baseLength && j < subLength){
if(j < 0 || base.charAt(i) == sub.charAt(j)){
i++;
j++;
}else {
j = next[j];
}
}
int result = j == subLength?i-j:-1;
return result;
} public static void main(String[] args) {
try {
String base = "ababghababa";
String sub = "ababap";//chinchilla,ababaaaba,
int result = matchOfKMP(base, sub);
System.out.println(result);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}

KMP算法实践与简单分析的更多相关文章

  1. KMP算法以及优化(代码分析以及求解next数组和nextval数组)

    KMP算法以及优化(代码分析以及求解next数组和nextval数组) 来了,数据结构及算法的内容来了,这才是我们的专攻,前面写的都是开胃小菜,本篇文章,侧重考研408方向,所以保证了你只要看懂了,题 ...

  2. KMP算法的一个简单实现

    今天学习KMP算法,参考网上内容,实现算法,摘录网页内容并记录自己的实现如下: 原文出处: http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93M ...

  3. 串的模式之kmp算法实践题

    给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出.如果找不到,则输出“Not ...

  4. Hash算法原理的简单分析

    哈希计算就是努力的把比较大的数据存放到相对较小的空间中.最常见的哈希算法是取模法.下面简单讲讲取模法的计算过程.比如:数组的长度是5.这时有一个数据是6.那么如何把这个6存放到长度只有5的数组中呢.按 ...

  5. kmp算法笔记(简单易懂)

    一般字符串比较长串m短串为n,那么用暴力方法复杂度为O(m*n) 但是kmp却可以达到O(m+n)!!!!!! 对于这个神奇的算法,我也是似懂非懂, 下面介绍一个简单的方法求kmp 1.求next数组 ...

  6. 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现

    一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想 ...

  7. KMP算法的一次理解

    1. 引言 在一个大的字符串中对一个小的子串进行定位称为字符串的模式匹配,这应该算是字符串中最重要的一个操作之一了.KMP本身不复杂,但网上绝大部分的文章把它讲混乱了.下面,咱们从暴力匹配算法讲起,随 ...

  8. 从有限状态机的角度去理解Knuth-Morris-Pratt Algorithm(又叫KMP算法)

    转载请加上:http://www.cnblogs.com/courtier/p/4273193.html 在开始讲这个文章前的唠叨话: 1:首先,在阅读此篇文章之前,你至少要了解过,什么是有限状态机, ...

  9. 温故KMP算法

    最近由于某些原因,又回顾了一次KMP算法.上一次回顾KMP算法还是在刷题的时候遇到的: http://blog.csdn.net/dacc123/article/details/50994611 在我 ...

随机推荐

  1. 只查看tomcat进程,不包括grep

    ps aux | grep tomcat  | grep -v "grep" | awk '{print $2}'

  2. 从Object和Function说说JS的原型链

    ECMAScript规定了两个特殊的内置对象:Object和Function.他们的特殊性在于,他们本身既是对象又是函数,而他们同时也是对象和函数的构造器.这种自己生自己的逻辑显然违反人性,如果还停留 ...

  3. [转载]在instagram上面如何利用电脑来上传图片

    原文地址:在instagram上面如何利用电脑来上传图片作者:小北的梦呓 我们都知道instagram是一个手机版的app,instagram官方不支持通过电脑来上传图片,而利用手机又很麻烦,那么如果 ...

  4. 【★】SPF(Dijkstra)算法完美教程

  5. WEB跨域资源共享:Cross-origin Resource Sharing(CORS)

    跨域资源共享(CORS):浏览器同源策略中的同源指协议+域名+端口三者完全一致,其中任何一个不同即为跨域 1. 浏览器同源政策是隔离潜在恶意文件的安全机制,限制信息传递和使用的边界,不是信息的保密机制 ...

  6. centos6.6配置rsync+sersync实现实时同步分布式多客户端分发同步

    1.sersync项目: sersync项目利用inotify与rsync技术实现对服务器数据实时同步到解决方案,其中inotify用于监控sersync所在服务器上文件系统的事件变化,rsync是目 ...

  7. 【Alpha】第三次Daily Scrum Meeting

    GIT 一.今日站立式会议照片 二.会议内容 1.确定开发人员负责开发模块 开发人员 开发模块 杨嘉成 注册登陆模块 吴文庆 服务模块 程志铭 个人中心 2.测试人员在开发人员完成该模块后紧跟测试 三 ...

  8. 团队作业4——第一次项目冲刺(Alpha版本) Day7

    首先和助教及老师表示抱歉,博客确实当时就写了,但是一直不算写好,因为这几天卡住了,预计实现的功能实现不了,进度跟不上,现在也在寻求解决方法. 1.站立式会议: 遇到的困难和收获:在开发的过程中其实遇到 ...

  9. 201521123073 《Java程序设计》第8周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 (1)集合里面获取对象的时候我们必须进行强制类型转换. List st ...

  10. 201521123030《Java程序设计》第4周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 控制可见性的4个访问修饰符 private -- 仅对本类可见 public -- 对所有类 ...