KMP算法(推导方法及模板)
介绍
克努斯-莫里斯-普拉特算法Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置。此算法通过运用对这个词在不匹配时本身就包含足够的信息来确定下一个匹配将在哪里开始的发现,从而避免重新检查先前匹配的字符。
此算法可以在O(n+m)时间数量级上完成串的模式匹配操作,其改进在于:每当一趟匹配过程中出现字符比较不等时,不需回溯i的指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的距离后,继续进行比较。
kmp的核心之处在于next数组,而为了方便理解,我先介绍KMP的思想
KMP匹配
当开始匹配时,如果匹配过程中产生“失配”时,指针i(原串的下标)不变,指针j(模式串的下标)退回到next[j] 所指示的位置上重新进行比较,并且当指针j退回至零时,指针i和指针j需同时加一。即主串的第i个字符和模式的第一个字符不等时,应从主串的第i+1个字符起重新进行匹配。
简单来说,就是两个串匹配,如果当前字符相等就比较两个字符串的下一个字符,如果当前匹配不相等时,就让j(待匹配串的下标)回到next[j] 的位置,因为我们已经知道next数组的作用是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的距离,如ababac与abac比较时i=4,j=4时不匹配,则利用next数组让j=2继续匹配而不用重新开始。(目前先不用管next数组的值时如何得到的,只要明白它的作用即可,下面回介绍)
所以我们可以写出kmp的代码
int KMP(char str[],char pat[])
{
int lenstr=strlen(str);
int lenpat=strlen(pat);
int i=1,j=1;
while(i<=lenstr)
{
if(j==0 || str[i]==pat[j]) //匹配成功继续往后匹配
++i,++j;
else
j=next[j]; //否则根据next数组继续匹配
if(j==lenpat) //说明匹配完成
return 1;
}
return 0;
}
接下来就是关键的求next数组了
next数组
首先,next数组取决于模式串本身而与相匹配的主串无关,我们可以对其递推得到。
网上讲next数组求解的博客一大堆,我就不那样从定义那一扯一大堆了,随便说一下如何推算的吧。
举个例子,如abacabc,首先,next[ 1 ]=0(下标从1开始),后面next[j]的值就看第j-1个字符是否与前面的匹配,如果匹配next[j]=next[j-1]+1,否则其他情况next[j]=1。这样说太笼统,我们看例子:
next[2]=1(第一个字符无法匹配,所以为1),
next[3]=1(第二个字符与第一个字符不相等),
next[4]=2(第三个字符与第一个字符相匹配,所以就等于next[3]+1),
next[5]=1(因为第4个字符与前面没有匹配的),
next[6]=2(同样第5个字符与第1个字符匹配),
next[7]=3(因为第6个字符b与第2个字符b匹配,同时由next[6]可知第5个字符与第1个字符同样匹配,即子串ab与ab匹配,故next[7]=next[6]+1)
下面给出几个例子,可以自己推导一下
abcdex
011111
abcabx
011123
ababaaaba
011234223
aaaaaaaab
012345678
如果理解了推导过程的话再回头看代码就好理解了,就算不理解也不要紧,先用着,过一段时间再去消化,下面是代码:
void getnext(char *pat)
{
int i=1,j=0;
int len=strlen(pat);
next[1]=0;
while(i<len)
{
if(j==0 || pat[i]==pat[j])
{
++i;
++j;
next[i]=j;
}
else
j=next[j];
}
优化
前面定义的next在某些情况下有缺陷,如模式串aaaab和主串aaabaaaab匹配时,仍有许多不必要的步骤,所以下面代码在这种情况做了优化:
void getnext(char *pat)
{
int i=1,j=0;
int len=strlen(pat);
next[1]=0;
while(i<len)
{
if(j==0 || pat[i]==pat[j])
{
++i;
++j;
if(pat[i]!=pat[j])
next[i]=j;
else
next[i]=next[j];
}
else
j=next[j];
}
模板
而下面是常用的模板,可以找到匹配下标与匹配次数,在与前面的略有些不同,其实就是next的值都减1罢了。
#include <iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char str[1000010],pat[1000010];//pat为模式串,str为主串
int Next[1000010]; //Next[x]下标x表示匹配失败处字符下标
//模式串pat的前缀与x位置的后缀的最大匹配字符个数-1
void GetNext(char *pat)
{
int LenPat = strlen(pat);
int i = 0,j = -1;
Next[0] = -1;
while(i < LenPat)
{
if(j == -1 || pat[i] == pat[j])
{
i++,j++;
Next[i] = j;
}
else
j = Next[j];
}
}
int KMP()//返回模式串pat在str中第一次出现的位置
{
int LenStr = strlen(str);
int LenPat = strlen(pat);
GetNext(pat);
int i = 0,j = 0;
int ans = 0;//计算模式串在主串匹配次数
while(i < LenStr)
{
if(j == -1 || str[i] == pat[j])
i++,j++;
else
j = Next[j];
if(j == LenPat)
{
//ans++; ans存放匹配次数,去掉return,最后返回ans
return i - LenPat + 1;
}
}
return -1;//没找到匹配位置
//return ans;//返回匹配次数。
}
int main()
{
scanf("%s%s",str,pat);
int i=KMP();
printf("%d\n",i);
return 0;
}
KMP算法(推导方法及模板)的更多相关文章
- KMP算法,匹配字符串模板(返回下标)
//KMP算法,匹配字符串模板 void getNext(int[] next, String t) { int n = next.length; for (int i = 1, j = 0; i & ...
- 什么是KMP算法?KMP算法推导
花了大概3天时间,了解,理解,推理KMP算法,这里做一次总结!希望能给看到的人带来帮助!! 1.什么是KMP算法? 在主串Str中查找模式串Pattern的方法中,有一种方式叫KMP算法 KMP算法是 ...
- KMP算法自我理解 和 模板
字符串 abcd abc abcd abc 匹配串 cdabcd 匹配串的 next 0 0 0 0 1 2: 开始匹配 abcd abc abcd abc cd abc d a,d 匹配失 ...
- 解读KMP算法
前后断断续续搞了5个月,每次都以为自己懂了, 但是要写的时候都不知从何下手,然后又是各种找博客,看帖子,所以这次试着用自己的语言写一个博客. 首先,KMP算法就是从一个模板字符串(S) 中匹配目标字符 ...
- KMP算法与传统字符串寻找算法
原理:KMP算法是一种模板匹配算法,它首先对模板进行便利,对于模板中与模板首字符一样和首字符进行标志-1,对于模板匹配中出现不匹配的若是第一轮检查标志为0,若不是第一轮检查标志为该元素与标志为-1的距 ...
- Luogu 3375 【模板】KMP字符串匹配(KMP算法)
Luogu 3375 [模板]KMP字符串匹配(KMP算法) Description 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来 ...
- [模板]KMP算法
昨天晚上一直在调KMP(模板传送门),因为先学了hash[关于hash的内容会在随后进行更(gu)新(gu)]于是想从1开始读...结果写出来之后一直死循环,最后我还是改回从0读入字符串了. [预先定 ...
- KMP算法(——模板习题与总结)
KMP算法是一种改进的模式匹配算法,相比于朴素的模式匹配算法效率更高.下面讲解KMP算法的基本思想与实现. 先来看一下朴素模式匹配算法的基本思想与实现. 朴素模式匹配算法的基本思想是匹配过程中如果该位 ...
- KMP算法模板&&扩展
很不错的学习链接:https://blog.csdn.net/v_july_v/article/details/7041827 具体思路就看上面的链接就行了,这里只放几个常用的模板 问题描述: 给出字 ...
随机推荐
- 1013MySQL监控利器-Innotop
转自 http://www.cnblogs.com/ivictor/p/5101506.html 安装过程中 可以使用 YUM INSTALL INNOTOP进行直接安装 Innotop是一款十分强大 ...
- java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.getXmlStandalone()Z解决办法
2019-05-20 23:02:20.168 |-INFO [http-nio-8001-exec-2] com.xxx.ecc.cloudbiz.service.payment.impl.Wei ...
- 使用大白菜U盘进入PE后再次重启电脑会留后门的清理方法
使用大白菜U盘进入PE后再次重启电脑会留后门,这个后门主要是自动下载安装一些软件,比如金山毒霸等. 清除方法: 1.每次用完PE重启前,清理以下地方: ①c:\Windows\xxxxx.exe(查看 ...
- 高效管理 Elasticsearch 中基于时间的索引——本质是在利用滚动模式做数据的冷热分离,热索引可以用ssd
高效管理 Elasticsearch 中基于时间的索引 转自:http://stormluke.me/es-managing-time-based-indices-efficiently/ 用 Ela ...
- java基本数据类型(二)和分支结构
基本数据类型(四类八种):不能为null一.整数型 byte----2的8次方 short----2的16次方 int----2的32次方 long----2的64次方二.浮点型 float----4 ...
- 移动端的click事件延迟触发的原理是什么?如何解决这个问题?
移动端的click事件延迟触发的原理是什么?如何解决这个问题? 原理 :移动端屏幕双击会缩放页面 300ms延迟 会出现点透现象 在列表页面上创建一个弹出层,弹出层有个关闭的按钮,你点了这个按钮关闭弹 ...
- Lucene中Analyzer语句分析
Lucene中Analyzer语句分析,利用lucene中自带的词法分析工具Analyzer,进行对句子的分析. 源代码如下: package com.test; import java.io.IOE ...
- 9.14[XJOI] NOIP训练33
今日9.14 洛谷打卡:大凶!!!(换个字体玩玩qwq) -------------------------------------------------------- 一个超颓的上午 今天又是fl ...
- html页面中苹果手机遇到数字换行、样式变形
在做项目中遇到过几回苹果手机读取html页面时,如果出现一串数字,html页面会折行.变形,最后发现是因为苹果手机的打电话功能,如果html上有数字的话,苹果手机会以为是电话号码,就会改变其样式只需要 ...
- c语言open()介绍
2013-09-0914:40:13 1. 头文件: #include <sys/types.h> #include <sys/stat.h> #include <fcn ...