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( ...
随机推荐
- 闲扯 Javascript 02 全选、不选、反选
<body> <input id="btn1" type="button" value="全选" /><br& ...
- Java --CountDownLatch简介
CountDownLatch 1.类介绍 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.用给定的计数 初始化 CountDownLatch.由于调用了 coun ...
- c语言string.h和memory.h某些函数重复问题
在C语言中,为了使用memset()函数,你是选择#include <string.h>还是<memory.h>?两个都可以,如何选择? <string.h>,标准 ...
- 17.1 Replication Configuration 复制:
17.1 Replication Configuration 复制: 17.1.1 How to Set Up Replication 17.1.2 Replication Formats 17.1. ...
- Android开发之SoundPool使用具体解释
使用SoundPool播放音效 假设应用程序常常播放密集.急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了.由于MediaPlayer存在例如以下缺点: 1) ...
- ios9怎么设置6位密码 ios9设置6位密码图文教程
在原来的 iOS 系统中,只有四位数字密码与复杂密码之分,而在 iOS9 系统中却多出了一个六位数字密码,那ios9怎么设置6位密码,今天小编就为大家带来ios9设置6位密码图文教程 在原来的 i ...
- OC中线程的状态相关
1.线程的状态NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; ...
- ASP.NET - 使用MqSql数据库
1. 首先需要安装mysql, 脚本之家下载地址: http://www.jb51.net/softs/2193.html 或者去mysql.com官网都可以,一路next,安装好后,有个简单配置,提 ...
- Zookeeper从入门到精通(开发详解,案例实战,Web界面监控)
ZooKeeper是Hadoop的开源子项目(Google Chubby的开源实现),它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护.命名服务.分布式同步.组服务等. Zookee ...
- 玩转大数据:深入浅出大数据挖掘技术(Apriori算法、Tanagra工具、决策树)
一.本课程是怎么样的一门课程(全面介绍) 1.1.课程的背景 “大数据”作为时下最火热的IT行业的词汇,随之而来的数据仓库.数据分析.数据挖掘等等围绕大数据的商业价值的利用逐渐成为 ...