KMP算法介绍
简介
KMP算法是D.E.Knuth、J.H.Morris和V.R.Pratt共同提出的,称之为Knuth-Morris-Pratt算法,简称KMP算法。该算法与Brute-Force算法相比有较大改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。
实现
1、从模式串t中提取加速匹配的信息
kmp就是通过模式串本身的特点来加速的,具体来说就是求next数组,next数组的定义如下:
$$next[j]=\begin{cases} -1 & 当j=0时\\MAX\{k \,|\, 0<k<j {\ } and {\ } "t_0t_1\cdot \cdot \cdot t_{k-1}"="t_{j-k}t_{j-k+1}\cdot \cdot \cdot t_{j-1}"\}&前后缀相等时\\0 &其它情况\end{cases}$$
next数组的求解过程如下:
- next[0]=-1(特殊值,标记),next[1]=0(j=1,在1~j-1的位置上没有字符,属于其它情况)
- 如果next[j] = k,表示有$"t_0t_1\cdot \cdot \cdot t_{k-1}"="t_{j-k}t_{j-k+1}\cdot \cdot \cdot t_{j-1}"$:
- 若$t_k=t_j$,即有$"t_0t_1\cdot \cdot \cdot t_{k-1}t_k"="t_{j-k}t_{j-k+1}\cdot \cdot \cdot t_{j-1} t_j"$,显然有$next[j+1]=k+1$。
- 若$t_k\neq t_j$,说明$t_j$之前不存在长度为$next[j]+1$的字串和开头字符起的字串相同,那么是否存在一个长度较短的字串和开头字符起的字串相同呢?设${k}'=next[k]$(回退),则下一步应该将$t_j$与$t_{{k}'}$比较:若$t_j=t_{{k}'}$,则说明$t_j$之前存在长度为$next[{k}']+1$的字串和开头字符起的字串相同;否则依此类推找更短的字串。知道不存在可匹配的字串,置$next[j+1]=0$。所以,当$t_k \neq t_j时,置$k=next[k]$
例如:
求模式串$t="aaaba"$的next数组。
解:
| j | 0 | 1 | 2 | 3 | 4 |
| t[j] | a | a | a | b | a |
| next[j] | -1 | 0 | 1 | 2 | 0 |
//char x[]是模式串
void pre_kmp()
{
int m = strlen(x);
int i = , j = nexts[] = -;
while (i < m)
{
while (j != - && x[i] != x[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
}
2、KMP算法的模式匹配过程
简单的说就是,若当前位置匹配则模式串和主串指针同时后移一位,若当前位置不匹配,则主串指针不动,模式串指针回退到next[i],如果回退的位置上仍不匹配继续回退。
大概这样:

//返回x在y中出现的次数(可重叠)
int KMP_Count() //x为模式串,y为主串
{
int i = , j = , ans = ;
int m = strlen(x), n = strlen(y);
pre_kmp();
while (i < n)
{
while (j != - && y[i] != x[j]) j = nexts[j]; //当前位置不同,j回退
i++; j++; //当前位置相同,i、j同时后移一位
if (j >= m)
{
ans++;
j = nexts[j];
}
}
return ans;
}
注:
- 匹配时分为主串可重复和主串不可重复,两者只是在找到匹配串时模式串的回溯位置不同
- next数组保证了真前缀和真后缀尽可能长的匹配,这样才能保证匹配时不会出现遗漏,同时模式串也能右移的更多
- pre_kmp求next数组时求了字符串最后一个字符的下一位,因为做题时经常需要这个值
复杂度
一般化结论:
- 一个周期内的比较次数:1 * (M - 1) + M
- 周期长度:M
- 周期个数:N/M
- 比较总次数: 周期个数 * 一个周期内额比较次数 = (2 - 1/M)*N < 2N
所以最坏情况下模式串中每个字符的平均比较次数小于2,所以比较部分的平均时间复杂度为O(N)。
求next数组的过程其实主串与主串比较(KMP是将主串与模式串匹配),所以时间复杂度为O(M)。
总的时间复杂度为O(M+N)。
参考链接:
KMP算法介绍的更多相关文章
- python KMP算法介绍
- BF算法与KMP算法
BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符:若不相等,则比较S的 ...
- KMP算法小结
最近看了一些关于KMP算法的资料,在此写一篇博客总计一下. 1.KMP算法介绍 KMP算法是一种字符串搜索的改进算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称 ...
- 浅谈KMP算法——Chemist
很久以前就学过KMP,不过一直没有深入理解只是背代码,今天总结一下KMP算法来加深印象. 一.KMP算法介绍 KMP解决的问题:给你两个字符串A和B(|A|=n,|B|=m,n>m),询问一个字 ...
- 算法(Java实现)—— KMP算法
KMP算法 应用场景 字符串匹配问题 有一个字符串str1 = " hello hello llo hhello lloh helo" 一个子串str2 = "hello ...
- 字符串与模式匹配算法(三):KMP算法
一.KMP算法介绍 KMP算法与前面的MP算法一脉相承,都是充分利用先前匹配的过程中已经得到的结果来避免频繁回溯.回顾一下MP算法,如下图的模式串偏移,当前模式字符串P的左端的p0与目标字符串T中tj ...
- KMP算法的工作流程介绍
最近又想起了KMP算法,原来一直没搞明白工作原理,现在总算是开点窍了,推荐大家看这篇文章,写的很简单易懂 推荐理由:简单明了,是我看过介绍KMP算法流程的所有文章中,最易懂的一篇(这篇文章仅仅是介绍了 ...
- 算法:KMP算法
算法:KMP排序 算法分析 KMP算法是一种快速的模式匹配算法.KMP是三位大师:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,所以取首字母组成KMP. 少部分图片来自孤~影 ...
- [Algorithm] 字符串匹配算法——KMP算法
1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...
随机推荐
- IJ:IJ来了2-调试开发环境
ylbtech-IJ:IJ来了2 1.返回顶部 1. 2. 3. 4. 2. 配置SVN返回顶部 1.SVN安装时,要选上command line client tools 2. 3. 4. 3. ...
- asp.net MVC 枚举类型的处理的几种方式
枚举类型本质上是int类型,整型,这是非常重要的一点. 可以使用(int)将它强制转换为 整形.如果要使用MVC5提供的新辅助方法@Html.EnumDropDownListFor()方法,就必须将枚 ...
- 将json文件转换成insert语句的sql文件
引入是要的maven依赖: <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <depend ...
- Pow(x, n) 位运算总结 典型
https://leetcode.com/problems/powx-n/ Implement pow(x, n), which calculates x raised to the power n ...
- 关于kindle无法连接上wifi的问题
家里换了宽带以后我发现kindle无法链接上WiFi了. 原因可能是我家使用的WiFi网络是1-11之间的信道,也有可能是运营商的问题(由于我是软件开发,对硬件和网络并不是很清楚,只能大概估计一下). ...
- Java中关键字continue、break和return的区别
Java中关键字continue.break和return的区别: continue:跳出本次循环继续下一次循环 break: 跳出循环体,继续执行循环外的函数体 return: 跳出整个函数 ...
- 针对IE浏览器里面CSS的Bug解决方法
IE6双倍边距bug 当页面内有多个连续浮动时,如本页的图标列表是采用左浮动,此时设置li的左侧margin值时,在最左侧呈现双倍情况.如外边距设置为10px, 而左侧则呈现出20px,解决它的方法是 ...
- [GZOI2016] 亚索的量子实验【分块】
第二题 亚索的粒子实验 [问题描述] 亚索是一名伟大的科学家,他最近在做一个粒子的实验,粒子初始有一定的能量,实验过程中倘若第i个粒子被注入k能量,那该粒子就会增加k能量,同时由于辐射作用,第2i,3 ...
- 洛谷 P3332 [ZJOI2013]K大数查询 || bzoj3110
用树套树就很麻烦,用整体二分就成了裸题.... 错误: 1.尝试线段树套平衡树,码农,而且n*log^3(n)慢慢卡反正我觉得卡不过去 2.线段树pushdown写错...加法tag对于区间和的更新应 ...
- [转][ASP.NET MVC]如何定制Numeric属性/字段验证消息
本文转自:http://www.cnblogs.com/artech/archive/2012/02/13/NumericPropertyValidation.html 对于一个Numeric属性/字 ...