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 在我 ...
随机推荐
- 常用按钮css
#openwx_btn { border: 0px; background-color: rgb(145, ...
- 团队作业8----第二次项目冲刺(Beta阶段) 第七天
BETA阶段冲刺第六天 1.小会议ing 2.每个人的工作 (1)昨天已完成的工作 完成查重部分 (2) 今天计划完成的工作 (3) 工作中遇到的困难: 尤少辉:在测试的时候发现了,文件名保存到数据 ...
- 201521123054《Java程序设计》第8周学习总结
1. 本周学习总结 2. 书面作业 List中指定元素的删除(题目4-1) 1.1 实验总结 每次删除时下标需要-1:原理如图 统计文字中的单词数量并按出现次数排序(题目5-3) 2.1 伪代码(简单 ...
- 201521123028 《Java程序设计》第3周学习总结
1. 本周学习总结 2. 书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...
- 201521123005 《Java程序设计》 第十一周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 Q1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...
- Optional变量初学者指南
苹果三周前发布了Swift. 从那时起,我一直在阅读Swift的官方指南,并在Xcode 6测试版中使用. 我开始喜欢Swift的简单和语法. 与我的团队一起,我仍然在研究新的语言,并看看它与Obje ...
- 多线程面试题系列(6):经典线程同步 事件Event
上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的"线程所有权"特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题.首先 ...
- 前端angularJS利用directive实现移动端自定义软键盘的方法
最近公司项目的需求上要求我们iPad项目上一些需要输入数字的地方用我们自定义的软键盘而不是移动端设备自带的键盘,刚接到需求有点懵,因为之前没有做过,后来理了一下思路发现这东西也就那样.先看一下实现之后 ...
- Socket类 以及 ServerSocket类 讲解
Socket类 套接字是网络连接的端点,套接字使应用可以从网络中读取数据,可以向网络中写入数据.不同计算机上的两个应用程序可以通过连接发送或接收字节流,以此达到相互通信的目的. 为了从一个应用程序向另 ...
- servlet_2
package com.atguigu.servlet; import java.io.IOException; import javax.servlet.Servlet;import javax.s ...