一、理解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. cocos2dx lua中异步加载网络图片,可用于显示微信头像

    最近在做一个棋牌项目,脚本语言用的lua,登录需要使用微信登录,用户头像用微信账户的头像,微信接口返回的头像是一个url,那么遇到的一个问题就是如何在lua中异步加载这个头像,先在引擎源码里找了下可能 ...

  2. JavaScript 的使用基础总结②DOM

    HTML DOM 通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素. 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HT ...

  3. 201521123022 《Java程序设计》 第七周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 Q1.ArrayList代码分析 Q1.1 解释ArrayList的contains源代码 ArrayLis ...

  4. Java 第六周总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  5. 201521123060《Java程序设计》第1周学习总结

    1. 本章学习总结 认识和了解了Java的发展进程: 了解了相关开发工具: 认识了JVM,JRE,JDK: 2. 书面作业 Q1.为什么java程序可以跨平台运行?执行java程序的步骤是什么?(请用 ...

  6. 201521123020《java程序设计》第1周学习总结

    1.本周学习总结 1.对JAVA的历史发展的了解 2.了解Java与C/C++的区别,Java语言所写程序较为繁琐,C/C++较为简洁. 3.安装java和jdk 2.书面作业 Q1.为什么java程 ...

  7. eclipse: eclipse导入工程出现大红叹号

    总结: 问题原因:工程中classpath中指向的包路径错误 解决办法:到BUILDPATH CONFIG````中,liberaies中 出现红色叉号的包为路径错误的包.到classpath中修改相 ...

  8. table相关的选择器 & children()与find()的区别 & 选择器eq(n)与nth-child(n)的差异

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  9. CustomDialog——一个多功能、通用、可自定义的Dialog

    CustomDialog--一个多功能.通用.可自定义的Dialog  依赖 compile 'com.github.SiberiaDante:CustomDialog:v1.0.1'  说明[Cus ...

  10. XML功能

    REF:https://www.baidu.com/link?url=_-UY8rZVAORlesKTth0F7C8LbvXCL4lSwz6vmQVnTEgmT06NFGdoaD9FbuEQhR7xG ...