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",我想知道,里面是否包含另一个字符串& ...
随机推荐
- Java 基本类型和对象类型的区别
Java 基本类型和对象类型的区别 基本类型: int long byte float double char boolean short 对象类型: Integer Long Byte Float ...
- 并不对劲的bzoj4817:loj2001:p3703:[SDOI2017]树点涂色
题目大意 有一棵\(n\)(\(n\leq10^5\))个节点的树,每个点有颜色\(c\),一开始所有颜色互不相同 要进行\(m\)(\(m\leq10^5\))次操作,每次操作是以下三种中的一种: ...
- openpyxl操作excel
[转] openpyxl库可以读写xlsx格式的文件,对于xls旧格式的文件只能用xlrd读,xlwt写来完成了. python有很多模块都是用来操作excel的,比如xlrd,xlwt,pyExce ...
- appium学习【四】:第一个appium脚本
#coding=utf-8 import os import HTMLTestRunner import unittest import time import sys from appium imp ...
- JSP+MySQL实例
转自:https://www.yiibai.com/jsp/jsp_mysql.html 在本章中,我们将讨论如何使用JSP访问数据库(这里以MySQL数据库为例).并假设您对JDBC应用程序的工作方 ...
- context:property-placeholder作用
原文地址:http://blog.sina.com.cn/s/blog_a0de59cf0101dqeb.html spring去加载,这个元素的写法如下: <context:property- ...
- 【192】PowerShell 相关知识
默写说明: 查询别名所指的真实cmdlet命令. Get-Alias -name ls 查看可用的别名,可以通过 “ls alias:” 或者 “Get-Alias”. 查看所有以Remove打头的c ...
- Java多线程系列八——volatile和ThreadLocal
参考资料: http://ifeve.com/java-memory-model-4/ http://www.infoq.com/cn/articles/java-memory-model-1 htt ...
- 徐州联赛选拔赛 - 计算IP地址值
题目链接 思路:这是一道非常简单的题目,直接用公式计算就好了.对于IP地址a.b.c.d,转换为十进制数就是(a<<24)|(b<<16)|(c<<8)|d.唯一要 ...
- 标准字符cp功能
#include<stdio.h> #include<fcntl.h> int main(int argc,char *argv[]) { FILE *src_fp,*des_ ...