浅谈c++中的KMP
所谓KMP,其实就是一种经过改进的模式串匹配算法(即在原串A中查找是否存在模式串B)
通常情况下,我们是这样匹配的
串A X Y Z X X Y Z X Y
串B X Y Z X Y
串A X Y Z X X Y Z X Y
串B X Y Z X Y
……
串A X Y Z X X Y Z X Y
串B X Y Z X Y
(其中红色代表第一次失去匹配的位置)
很明显这样匹配是非常低效的
为了优化这种算法,我们考虑令每次将B串右移的位置尽可能长
那么现在问题来了
移动到哪里才算最长??
首先我们保证两个原则:
(1)保证不会漏掉解
(2)向右移尽可能长
首先我们为了右移尽量长,采用从右向左贪心的方式,并设从失配位置到移动位置的距离为k,要求满足B[1~k]==B[j-k~j]
由于前j位均已匹配,所以A[j-k~j]==B[j-k~j]
为了保证移动结束后字符串在可预见的范围内均已匹配,要求A[j-k~j]==B[1~k]
大概就是这样:(图中i、j为失配位置)
(此时k=2)
为了保证不会漏掉解,假设B串头指针移动前为j1,移动后为j2
若j1~j2范围内存在可以匹配到B的子串,那么设这个子串开始的指针为j3,满足j3~j3+strlen(B)==B
那么此时失配位置应在j3,不在原失配位置
注意如果当j<0时仍然找不到匹配位置应从i后面寻找位置进行匹配
但这样依然很慢所以我们进入重点
对于每个k来讲很明显只和B串有关
所以我们利用一个nxt数组 nxt[j]表示B串前j位对应的k
这其实就是两个B串在互相进行匹配的过程
上代码
//这里数组从1开始
j=;
for(i=;i<n;i++)
{
while(j> && a[i+]!=b[j+]) j=nxt[j];//j未减小到0且不能继续匹配,减小j的值
if(a[i+]==b[j+]) j++;//能继续匹配,j的值增加
//若j==0仍不能匹配,由于循环i的值会自动增加
if(j==m)//找到一处匹配
printf("%d\n",i+-m+);//输出子串在主串中的位置
j=nxt[j];//继续匹配
} 这是代码1
匹配,输出位置
//这里数组从1开始
j=;
for(i=;i<n;i++)
{
while(j> && a[i+]!=b[j+]) j=nxt[j];//j未减小到0且不能继续匹配,减小j的值
if(a[i+]==b[j+]) j++;//能继续匹配,j的值增加
//若j==0仍不能匹配,由于循环i的值会自动增加
if(j==m)//找到一处匹配
{
printf("%d\n",i+-m+);//输出子串在主串中的位置
j=;//从头开始匹配,保证不重复
}
}
如果若干子串在主串中的位置不能重复,只需将j=nxt[j]改成j=0即可
//这里数组从1开始
p[]=j=;
for(i=;i<m;i++)
{
while(j> && b[i+]!=b[j+]) j=nxt[j];//j未减小到0且不能继续匹配,退一步
if(b[i+]==b[j+]) j++;//能继续匹配,j的值增加
//若j==0仍不能匹配,由于循环i的值会自动增加
nxt[i+]=j;//nxt数组赋值
} 这时代码3
预处理nxt数组
有没有觉得预处理和匹配的代码很像?Q_Q
浅谈c++中的KMP的更多相关文章
- 浅谈Java中的equals和==(转)
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- 浅谈Java中的对象和引用
浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...
- 浅谈Java中的equals和==
浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...
- 转【】浅谈sql中的in与not in,exists与not exists的区别_
浅谈sql中的in与not in,exists与not exists的区别 1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表 ...
- 浅谈iOS中的userAgent
浅谈iOS中的userAgent User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- 浅谈sql中的in与not in,exists与not exists的区别
转 浅谈sql中的in与not in,exists与not exists的区别 12月12日北京OSC源创会 —— 开源技术的年终盛典 » sql exists in 1.in和exists ...
- 浅谈Java中的深拷贝和浅拷贝(转载)
浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...
随机推荐
- struts1和struts2安全线
Servlet的生命周期是"初始化->init->service->destroy->卸载". 这里大家都知道,我们在web.xml里面定义一个servle ...
- C++ 中间statickeyword
static顾名思义是一个静态的含义.在此我想谈谈相关的系统statickeyword角色,当然,这主要是对语言的发展C与C++角色,在信息方面的作用等方面,请另找.在评论中肯定有不恰当,请大胆地抛砖 ...
- 自定义 DependencyProperty 与 RoutedEvent
原文:自定义 DependencyProperty 与 RoutedEvent //自定义依赖属性 class MyBook : DependencyObject//依赖属性必须派生自Dependen ...
- Marker
# 样例 <?xml version="1.0" encoding="UTF-8"?> <Configuration status=" ...
- HTTP协议-请求报文
- python3 提示No module named _sqlite3
yum install sqlite-devel 下载python3.6.3 重新编译安装 ./configure --enable-loadable-sqlite-extensions & ...
- android x86 7.0 32bit调试apk时出现的错误
detected problems with app native libraries libavcodec.so:text relocationslibavutil.solibswresample. ...
- Android零基础入门第37节:初识ListView
原文:Android零基础入门第37节:初识ListView 之前我们学习的一些UI组件都比较简单,但是在实际开发中,会经常遇见列表界面设计,如通讯录.电话列表.信息列表等.那么从本节开始来详细学习列 ...
- eclipse 插件编写(四)
前言 前面几篇文章讲了下如果编写简单的eclipse插件,如创建插件项目.编写右键弹出菜单等功能,接下来主要写一下如何生成代码的功能,这一片的功能跟插件本身的编写关联不太大,主要处理插件之后的业务内容 ...
- CRS-2800: Cannot start resource 'ora.asm' as it is already in the INTERMEDIATE state on server ‘RAC02’
在安装ORACLE RAC的Grid Infrastructure时,在节点1运行/u01/app/11.2.0/grid/root.sh正常,当在节点2运行/u01/app/11.2.0/grid/ ...