算法:模式匹配之KMP算法
前言:
昨天看到《算法导论》里的第32章:字符串匹配,说到一个关于字符串匹配的很好的算法——KMP。关于KMP的内存含意以及KMP的来源,不是本文讲述的范畴,请感兴趣的读者自行查阅相关资料。
本文主要是来说明KMP算法的思路和实现过程,以及它相比于朴素的字符串模式匹配存在的优势。
本文链接:http://blog.csdn.net/lemon_tree12138/article/details/48488813 -- 编程小笙
--转载请注明出处
朴素模式匹配算法:
1.思路分析
朴素的字符串模式匹配就是传统的算法——逐个比较。因为使用了嵌套循环,所以效率比较低。
2.代码实现
public class SimpleMatching {/*** 采用朴素的字符串匹配算法查找子字符串* * @param T* 主字符串* @param P* 匹配模式字符串* @return* 匹配成功的所有位置*/public List<Integer> getIndexOfPinT(String T, String P) {if (Tools.isEmptyString(T) || Tools.isEmptyString(P)) {return null;}List<Integer> indexs = new ArrayList<Integer>();char[] t = T.toCharArray();char[] p = P.toCharArray();for (int i = 0; i <= t.length - p.length; i++) {for (int j = 0; j < p.length; j++) {if (t[i + j] == p[j]) {if (j == p.length - 1) {indexs.add(i);}continue;}break;}}return indexs;}
}
我们假定主字符串的长度为n,匹配模式字符串的长度为m。那么对于上面的算法,时间复杂度就是O(m*n)。对于一些需求不太严苛或是m,n比较小的情况下。这种算法还是可以接受的。但是如果不是上述情况,这样的一个时间复杂度可能还是略显尴尬。下面我就来介绍一下改进过后的KMP算法。
KMP模式匹配算法:
1.思路分析
KMP算法的关键是为我们排除了一些重复匹配,使用主字符串的匹配位置“指针”不需要回溯。这里不妨列举一个小例子。
主字符串T:fababadaaswababaca
匹配模式P:ababaca
假使此时我们正在匹配T的第7位(fababa[d]aaswababaca)和P的第6位(ababa[c]a)。而且匹配失败了。针对朴素的匹配模式是T的“指针”回溯到(fa[b]abadaaswababaca),P的“指针”回溯到([a]babaca)。这无疑是浪费了很多的时间。
我们重新检查一下P(ababaca),当我们开始匹配第6位的时候,之前的5位已经匹配完成。而且,[aba]baca = ab[aba]ca!那么针对于T而言,fab[aba]daaswababaca这三位是已经匹配过了,我们在把与之前匹配相等的字符串移至此处时,是不是就说明,这几个字符串是不需要再匹配了。
当我们知道了在匹配的过程中,有一些字符是不需要再匹配了的时候,接下来就是重头戏了。如何让这些已经匹配过的字符串不再重复匹配?
通过上面的分析,其实已经暗含了解决方案。就是我们要知道匹配模式中,每个最优前缀(关于最优前缀可以参考《算法导论》32章内容)S中,S的不为自身的最长的一个等于最优后缀(关于最优后缀可以参考《算法导论》32章内容)的最优前缀SS。这句话可能听起来有一些绕口,下面通过一个实例来说明:
匹配模式P:ababaca
我们选取P的一个最优前缀S = ababa,那么SS = aba.因为SS是S的最优前缀,也是S的最优后缀,而且是最长的。
上面就是关于KMP匹配模式的思路分析,如果你感觉这里有一些枯燥乏味或是阅读困难(对此,我对我拙劣的文字描述表示一些歉意)。下面可以在代码中寻找大家所契合的地方,因为逻辑是想通的嘛。
2.最优前缀的形式:
Index 0123456
P ABABACA
Next 0012301
3.代码实现
(1)获得字符串中的每个最优前缀子字符串中的最长的最优前缀等于最优后缀的长度
/*** 获得字符串中的每个最优前缀子字符串中的* 最长的最优前缀等于最优后缀的长度* * @param text* 待计算的字符串* @return* 返回最长的最优前缀等于最优后缀的长度数组*/public int[] getNext(String text) {if (Tools.isEmptyString(text)) {return null;}int[] lengths = new int[text.length()];for (int i = 0; i < text.length(); i++) {String sub = text.substring(0, i + 1);int maxLen = 0;for (int j = 0; j < sub.length() - 1; j++) {String subChild = sub.substring(0, j + 1);if (sub.endsWith(subChild) && subChild.length() > maxLen) {maxLen = subChild.length();}}lengths[i] = maxLen;}return lengths;}
(2)获得字符串P在字符串T中出现的所有位置
/*** 获得字符串P在字符串T中出现的所有位置* * @param T* 主字符串* @param P* 匹配模式字符串* @return* 匹配成功的所有位置*/public List<Integer> getIndexOfPinT(String T, String P) {if (Tools.isEmptyString(T) || Tools.isEmptyString(P)) {return null;}List<Integer> indexs = new ArrayList<Integer>();char[] t = T.toCharArray();char[] p = P.toCharArray();int[] next = getNext(P);int indexT = 0;int indexP = 0;while (indexT < t.length) {if (t[indexT] == p[indexP]) {indexP++;indexT++;} else {if (indexP == 0) {indexT++;} else {indexP = next[indexP - 1];}}if (indexP == p.length) {indexs.add(indexT - indexP);indexP = 0;}}return indexs;}
参考说明:
1.《算法导论》
2.Knuth–Morris–Pratt algorithm
源码下载:
对于上面的描述,如果你还没有完全理解,可以在下面的链接中下载与本文相关的源码进行参考学习.
http://download.csdn.net/detail/u013761665/9110859
算法:模式匹配之KMP算法相关推荐
- javaKMP算法(含KMP算法代码)
目录 一:应用场景-字符串匹配问题 二:暴力匹配算法 三:KMP 算法介绍 四:KMP 算法最佳应用-字符串匹配问题 字符串匹配问题: 思路分析图解 五:代码展示 一:应用场景-字符串匹配问题 字符串 ...
- 字符串的模式匹配,KMP算法
KMP算法是模式匹配的一种改进的算法,所谓的模式匹配也就是对于两个字符串主串S和模式串T.从主串的S的pos个字符起和模式串中的第一个字符进行比较,如果相等,则继续比较后面的字符,否则从主串的下一个字 ...
- 【模式匹配】KMP算法的来龙去脉
1. 引言 字符串匹配是极为常见的一种模式匹配.简单地说,就是判断主串T中是否出现该模式串P,即P为T的子串.特别地,定义主串为T[0-n−1],模式串为P[0-p−1],则主串与模式串的长度各为n与 ...
- 串的模式匹配(KMP算法)
[问题描述] 串的模式匹配算法实现(KMP算法) [输入形式] 第一行输入主串s: 第二行输入模式串t: 第三行输入起始位置pos: [输出形式] 输出模式串t的next值(以空格分隔) 输出模式匹配 ...
- C语言-模式匹配(KMP算法)
什么是KMP算法? KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,简称KMP算法.KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与 ...
- 串的模式匹配、KMP算法、nextval数组求法
一.暴力匹配 #include <iostream> using namespace std; #define MAXLEN 255 typedef struct{char ch[MAXL ...
- 【数据结构和算法笔记】KMP算法介绍
BF暴力算法: 当模式串位i与目标串i比较时两字符不相等,则i的移动方式:i=i-j+1 j的移动方式:j=0 KMP算法简介: ●KMP模式匹配中,当模式串位j与目标串位i比较两字符不相等 i ...
- python实现Trie 树+朴素匹配字符串+RK算法匹配字符串+kmp算法匹配字符串
一.trie树应用: 相应leetcode 常用于搜索提示,如当输入一个网址,可以自动搜索出可能的选择.当没有完全匹配的搜索结果,可以返回前缀最相似的可能. 例如三个单词app, apple, add ...
- kmp算法 php,漫画KMP算法-程序员小灰
// KMP算法主体逻辑.str是主串,pattern是模式串 public static int kmp(String str, String pattern) { //预处理,生成next数组 i ...
最新文章
- 使用 JMeter 进行压力测试
- 【sublime Text】关闭sublime的更新提醒和激活提醒
- 关于Mybatis的各种配置文件
- 粒子文字特效css,CSS3 粒子效果
- 每日一题:leetcode80.删除有序数组中的重复元素贰
- 2014年广州科目三道路驾驶技能考试/广汕路科目三路考系统操作和评判指南
- 国产毫米波雷达领域的领头羊,木牛科技将在明年量产77GHz汽车雷达
- ajax回调函数有时成功有时失败,javascript - Ajax 回调函数行为随机。我做错了什么?...
- [置顶] 手机通过socket控制电脑关机,重启,注销等功能
- 【主成分分析法】NLPer的断舍离(下篇)
- 计算机游戏测试软件,你的电脑能不能吃鸡,两款软件很简单就能测试出来
- 汇编_stack的使用
- JAVA 使用aspose.cad将dwg文件转PDF(每个布局转为一页)
- 器件基础知识——电阻
- java实现即时通讯_java实现WebSocket即时通信
- Csico IPPS 测试程序 autodialer.jsp
- 脉冲神经网络(SNN)论文阅读(一)-----Going Deeper With Directly-Trained Larger Spiking Neural Networks
- OSPF的DR/BDR的选举规则,数据包,接口网络
- lv官网编码查询_老太太拿LV买菜装大葱!结果闺女被抓了......
- size balanced tree (平衡二叉树) ----- 傻X树----陈启峰论文
热门文章
- 【计算机网络笔记】计算机网络体系与参考模型
- ubuntu中pycharm打不开的的处理方法
- 序列密码体制——密码学笔记(三)
- (53)进程结构体EPROCESS,擦除 DebugPort 实现反调试,ActiveProcessLinks 断链实现进程隐藏
- 【CTF解题】BCTF2018-houseofatum-Writeup题解
- MySQL DISTINCT:去重(过滤重复数据)
- 【MySQL】常用配置
- 微程序控制器原理(增量方式和断定方式结合法)
- 197. 阶乘分解【数论】
- 1030 Travel Plan (30 分) 【难度: 中 / 知识点: 最短路】