KMP算法实践与简单分析
一、理解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算法实践与简单分析的更多相关文章
- KMP算法以及优化(代码分析以及求解next数组和nextval数组)
KMP算法以及优化(代码分析以及求解next数组和nextval数组) 来了,数据结构及算法的内容来了,这才是我们的专攻,前面写的都是开胃小菜,本篇文章,侧重考研408方向,所以保证了你只要看懂了,题 ...
- KMP算法的一个简单实现
今天学习KMP算法,参考网上内容,实现算法,摘录网页内容并记录自己的实现如下: 原文出处: http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93M ...
- 串的模式之kmp算法实践题
给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出.如果找不到,则输出“Not ...
- Hash算法原理的简单分析
哈希计算就是努力的把比较大的数据存放到相对较小的空间中.最常见的哈希算法是取模法.下面简单讲讲取模法的计算过程.比如:数组的长度是5.这时有一个数据是6.那么如何把这个6存放到长度只有5的数组中呢.按 ...
- kmp算法笔记(简单易懂)
一般字符串比较长串m短串为n,那么用暴力方法复杂度为O(m*n) 但是kmp却可以达到O(m+n)!!!!!! 对于这个神奇的算法,我也是似懂非懂, 下面介绍一个简单的方法求kmp 1.求next数组 ...
- 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现
一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想 ...
- KMP算法的一次理解
1. 引言 在一个大的字符串中对一个小的子串进行定位称为字符串的模式匹配,这应该算是字符串中最重要的一个操作之一了.KMP本身不复杂,但网上绝大部分的文章把它讲混乱了.下面,咱们从暴力匹配算法讲起,随 ...
- 从有限状态机的角度去理解Knuth-Morris-Pratt Algorithm(又叫KMP算法)
转载请加上:http://www.cnblogs.com/courtier/p/4273193.html 在开始讲这个文章前的唠叨话: 1:首先,在阅读此篇文章之前,你至少要了解过,什么是有限状态机, ...
- 温故KMP算法
最近由于某些原因,又回顾了一次KMP算法.上一次回顾KMP算法还是在刷题的时候遇到的: http://blog.csdn.net/dacc123/article/details/50994611 在我 ...
随机推荐
- 【Alpha】第五次Daily Scrum Meeting
GIT 一.今日站立式会议照片 二.会议内容 今天对昨天会议上产生的分歧进行了意见统一,每个人都阐述了自己的见解与看法,对,大家确实希望要做出挑礼物这样一个小程序就要尽力做到最好,但也对一些功能的实现 ...
- 团队作业10——项目复审与事后分析(Beta阶段)
一.Beta阶段项目复审 http://www.cnblogs.com/womenshuodedoudui/p/7001208.html 二.事后诸葛分析 http://www.cnblogs.com ...
- 201521145048《Java程序设计》第5周学习总结
1. 本章学习总结 2. 书面作业 Q1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误.并分析输出结果. 错误 ...
- 201521123095《java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结上课内容. 对于一个系统中,对于名词大多为类或属性,对于动词大多为方法. 1.3 注释的应用 使用类的注释与 ...
- 201521123004 《Java程序设计》第3周学习总结
1. 本周学习总结 (1)①使用构造函数(constructor) eg:Date now = new Date(); new Date(); //创建了一个Date对象 now是Date类型变量,存 ...
- Java课设-购物车系统
1.团队课程设计博客链接 /[博客链接]http://www.cnblogs.com/yayaya/p/7062197.html 2.个人负责模板或任务说明 1.建立Action类 2.购物车的属性 ...
- Servlet一些基础
Servlet 是一套规范,规定了如何通过Java代码来开发动态网站,并由 javax.servlet 和 javax.servlet.http 两个包中的类来实现. servlet是一个服务器端组建 ...
- linux fork两次避免僵尸进程的程序(简单)
#include<stdio.h> #include<unistd.h> int main() { pid_t pid,pid1; int status; ) { printf ...
- mybatis入门篇基——基本配置与参数说明
Mybatis 好吧这是我第一次写这种文章~如果有不足和错误之处欢迎评论,指点.今天想谈谈关于mybatis的一些基础入门知识. 进入正题~~: a.关于mybatis: 我个人觉得mybatis深得 ...
- angular smart-table组件如何定制化之初步研究
table表运用在后台管理用得频繁,一般bootstrap的class="table"就能满足样式需求以及分页需求,但是每个产品经理需求不一样,比如说分页:bootstrap分页实 ...