KMP 知识点总结
KMP算法是BF算法的改进,主要是消除了主串指针的回溯,提高算法效率。
先简单介绍一下BF算法:
基本思路:
从目标串s的第一个字符开始和模式串的第一个字符比较,相等逐个比较后续字符,否则从目标串的第二个字符开始从新与模式串的第一个字符进行比较。以此类推。。
其时间复杂度为O(m*n)
BF-CODE:
int BF(char s[],char t[])
{
int i=,j=;
int lens=strlen(s);
int lent=strlen(t);
while(i<lens&&j<lent)
{
if(s[i]==t[j])//继续匹配下一个字符
{
i++;
j++;
}//主串和子串依次匹配下一个字符
else
{
i=i-j+;//主串从下一个位置开始匹配
j=;//子串从头开始匹配
}
}
if(j>=lent)
return (i-lent);
else
return -;
}
KMP算法:
如何消除主串指针的回溯呢?需要分析模式串t,对于t的每个字符t[j],若存在一个整数K,使得模式t中k所指字符之前的k个字符依次与tj的前面k个字符相同,并与主串s中i所指的字符之前的k个字符相等。那么就可以利用这种信息避免不必要的回溯了。这种信息我们把它记录在模式串的next数组中,那么如何来求next数组呢?
怎么求串的模式值next[n]
GET-NEXT CODE:
void get-next(char s[],char t[])
{
int j,k;
j=;
k=-;
next[]=-;
int lent=strlen(t);
int lens=strlen(s);
while(j<lent-)
{
if(k==-||t[j]==t[k])
{
j++;
k++;
next[j]=k;
}
else
k=next[k];
}
}
kmp算法的思想是:设s为目标穿,t为模式串,并设i,j指针分别指示目标串和模式串中正待比较的字符,令i,j的初始值均为0 ,若有s[i]=t[j],则i,j分别增加1,否则,j再退回到j=next[j]的位置,继续比较。直到出现下面两种情况:1.j退回到某个j=next[j]的位置时有s[i]=t[j],则指针各增加一后继续匹配,2.j退回到j=-1,令指针各增加1,下一次比较s[i+1]和t[0].时间复杂度是O(N+M).
KMP-CODE:
int kmp(char s[],char t[])
{
int lent=strlen(t);
int lens=strlen(s);
int i=,j=;
while(i<lens&&j<lent)
{
if(j==-||s[i]==t[j])
{
i++;
j++;
}
else
j=next[j];//i不变j退后
}
if(j>=lent)
return (i-lent);//返回匹配模式串的首字符下标
else
return -;
}
kmp算法基本讲完了,下面来说说Kmp的几个应用:
1.求最小循环节和最大重复次数(此段非原创,摘自http://www.cnblogs.com/jackge/archive/2013/01/05/2846006.html)
在KMP算法的使用中,首要任务就是获取一个字符串的next数组,所以我们得明白next数组的含义(最好的方法是自己弄个例子,在草稿纸上模拟一下),在这里,通俗一点 讲,next[k] 表示,在模式串的 k 个字符失配了,然后下一次匹配从 next[k] 开始(next[k] 中保存的是该失配字符的前一个字符在前面出现过的最近一次失配的字符后面的 一个字符的位置,有点绕口,自己写个例子看看就明白了,也可以继续往下看,有介绍,然后再自己尝试写写 )。
至于next数组为什么可以用来求重复前缀呢,而且求出来的重复前缀是最小的呢?
我们来看一下求next数组的代码:
void getnext(int len){
int i=,j=-;
next[]=-;
while(i<len){
if(j==- || str[i]==str[j]){
i++;j++;
next[i]=j;
}else
j=next[j];
}
}
个人认为,next数组在求解的过程中,用到了KMP的思想,当前失配了,就回溯到上一个next,请见 j=next[j] ,先说个结论,如果到位置 i ,如果有 i%(i- next(i))==0 , 那说明字符串开始循环了,并且循环到 i-1 结束,为什么这样呢?
我们先假设到达位置 i-1 的时候,字符串循环了(到i-1完毕),那么如果到第i个字符的时候,失配了,根据next数组的求法,我们是不是得回溯?
然而回溯的话,由于字符串是循环的了(这个是假定的),next[i] 是不是指向上一个循环节的后面一个字符呢??
是的,上一个循环节的末尾是 next[i]-1 ,然后现在循环节的末尾是 i-1 ,然么循环节的长度是多少呢?
所以,我们有 (i - 1) - ( next[i] - 1 ) = i - next[i] 就是循环节的长度(假设循环成立的条件下),但是我们怎么知道这个循环到底成立吗?
现在我们已经假设了 0————i-1 循环了,那么我们就一共有i 个字符了,如果有 i % ( i - next[i] ) == 0,总的字符数刚好是循环节的倍数,那么说明这个循环是成立的。
注意还有一点,如果 next[i] == 0,即使符合上述等式,这也不是循环的,举个反例
0 1 2 3 4 5
a b c a b d
-1 0 0 0 1 2
下标为1,2,3的next值均为0,那么 i%(i-next【i】)=i%i==0,但是这个并不是循环。
解释完毕,然后再来看下,为什么求出来的循环节长度是最小的呢?
因为next数组失配的时候,总是回溯到最近的循环节,所以i-next【i】就是最小的循环节长度
为什么求出来的循环次数是最多的呢?
循环节长度是最小的了,那么循环次数肯定是最多的了。
总结一下,如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 则说明字符串循环,而且
循环节长度为: i - next[i]
循环次数为: i / ( i - next[i] )
There is a meaning for wings that cannot fly,it's a previous memory of when you once flew through the sky.这篇博文写得挺认真的,希望大家多多指点~噶呜~~
KMP 知识点总结的更多相关文章
- KMP 知识点整理
1.扩展KMP 2.最大表示法 3.最小表示法 (扩展KMP) hdu2594 模板题 #include <iostream> #include <cstdio> #incl ...
- [知识点]KMP算法
// 此博文为迁移而来,写于2015年5月24日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w1iw.html 1.前 ...
- 链表、栈、队列、KMP相关知识点
链表.栈与队列.kmp; 数组模拟单链表: 用的最多的是邻接表--就是多个单链表: 作用:存储树与图 需要明确相关定义: 为什么需要使用数组模拟链表 比使用结构体 或者类来说 速度更快 代码简洁 算法 ...
- KMP算法简明扼要的理解
KMP算法也算是相当经典,但是对于初学者来说确实有点绕,大学时候弄明白过后来几年不看又忘记了,然后再弄明白过了两年又忘记了,好在之前理解到了关键点,看了一遍马上又能理解上来.关于这个算法的详解网上文章 ...
- 4种字符串匹配算法:KMP(下)
回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...
- 再谈KMP
昨天讲解了字典树和AC自动机后感觉整个人都蒙掉了.还好就是自己今天在网上看见一篇对KMP讲解非常详细的帖子,果断收藏.(点击这里查看) 然后代码的实现也就简单分析一些了,具体的知识点大家直接自己链接过 ...
- 数据结构学习之字符串匹配算法(BF||KMP)
数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 编写出BF暴力匹配.KM ...
- KMP模板实现
看了出题知识点才发现自己连KMP都没有好好的理解,甚至一共就打过一次板子=-= 于是照着之前的课件学了一学...发现没怎么弄懂qwq 我太弱啦! 找了一篇自认为全网最好的介绍 觉得写得很棒 字符串匹配 ...
- JSOI2020备考知识点复习
我太菜了qaq,我好爱咕咕咕啊 在NOIP2018爆炸后,我只能指望着在JSOI2019JSOI2020上咸鱼翻身(flag*1) 所以,我要开始复习学习(flag*2) 此博客文会不定时更新qaq( ...
随机推荐
- docker学习笔记1:docke环境的查看
本文的操作是在ubuntu操作系统下的. 一.环境检查 当登录一个安装了docker的机器后,首先我们要检查下docker环境如何. 1.命令:docker -v 上述命令返回安装的docker的版本 ...
- windows进程清理脚本
公司统一配的笔记本Thinkpad T440p,超级难用,常常内存占满.硬盘卡死,还管不了机!心里那个不爽啊!哎,不说了. 自己写了个脚本,用来强制关闭不须要的进程. 脚本例如以下: -------- ...
- 如何在Windows上配置EBS R12.1.3的OAF开发环境
1.找到想要开发的EBS OAF扩展对应的PATCH,可以参照下面的Note,因为我要做的是R12.1.3的开发,所以要下载p9879989_R12_GENERIC OA Framework - Ho ...
- Tomcat 7最大并发连接数的正确修改方法(转)
几乎所有的中文网页都介绍,要修改Tomcat的默认最大并发连接数,应该进行如下设置(实际上这些步骤是错误的): -------------------------------------------- ...
- premake在Ubuntu和GCC环境下创建简单的C++工程
由于premake基于lua脚本,为了方便编辑lua脚本,我在emacs24中利用package system安装了lua-mode. 然后创建config.lua文件,填入下面这段,主要来自:htt ...
- linux命令:ftp
1. 登录: ftp IP_ADDR : 根据提示输入USER_NAME PASS_WORD 或: ftp -i -n IP_ADDR user USER_NAME PASS ...
- 重操JS旧业第八弹:面向对象与继承
js里面没有语言语法层面的继承机制,但这并不意味着js就不能实现继承,利用js属性和方法动态性来模拟实现继承,通过总结大概有如下方法实现: 1 原型链继承 我们知道原型在对象中扮演着重要的角色,函数本 ...
- LPCTSTR
LPCTSTR类型: L表示long指针 这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都是为了兼容 ...
- 极限挑战—C#100万条数据导入SQL SERVER数据库仅用4秒 (附源码)
原文:极限挑战-C#100万条数据导入SQL SERVER数据库仅用4秒 (附源码) 实际工作中有时候需要把大量数据导入数据库,然后用于各种程序计算,本实验将使用5中方法完成这个过程,并详细记录各种方 ...
- WPF Popup 置顶问题
原文 WPF Popup 置顶问题 问题: 使用wpf的popup,当在popup中弹出MessageBox或者打开对话框的时候,popup总是置顶,并遮住MessageBox或对话框. 解决: 写如 ...