浅谈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 假如说你想复制一个简单变量.很简单: ...
随机推荐
- 一款天气app的温度曲线图的实现
原文:一款天气app的温度曲线图的实现 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/tyhzsd/article/details/50544639 ...
- .NET 上传并解析CSV文件存库
1.前端: 放置浏览按钮 <div class="row inner_table text-center"> <input id="fileId&quo ...
- WPF中的Application类。
原文:WPF中的Application类. Application对象用的名称空间是system.windows 1.手动创建Application对象步骤. 1.1).把项目中的App.Xaml文件 ...
- 【C#】解决MouseHook捕获鼠标动作,在有些电脑上SetWindowsHookEx失败返回0的问题
原文:[C#]解决MouseHook捕获鼠标动作,在有些电脑上SetWindowsHookEx失败返回0的问题 最近在debug鼠标位置捕获的功能时发现在其中的一台开发电脑上,SetWindowsHo ...
- 图像滤镜艺术---(Instagram)1977滤镜
原文:图像滤镜艺术---(Instagram)1977滤镜 图像特效---(Instagram)1977滤镜 本文介绍1977这个滤镜的具体实现,这个滤镜最早是Instagram中使用的 ,由于Ins ...
- ORA-09925: Unable to create audit trail file
当我修改ORACLE_SID为新的SID,想进行数据库还原时,用sqlplus报如下错误 [oracle@dbtest ~]$ sqlplus / as sysdba SQL Production : ...
- 卸载win10内置windows app的方法
原文:卸载win10内置windows app的方法 2015年,微软推出了windows10操作系统,其以漂亮的界面.良好的操作方式.方便的推送升级迅速获得了好多人的好评,因此,好多同学都换了win ...
- C#二分查找法 破洞百出版本
二分查找法在数据繁多的数据中查找是一种快速的方法,每次查找最多需要的次数 为2的n次方小于总个数. 当然是有前提的,就是需要把数据先排好序,这里指的都是数值型的数据. 基本思想就是把需要找的值与排序好 ...
- 解析 Qt 字库移植并能显示中文 (下篇)
原文http://mobile.51cto.com/symbian-272563.htm 本文介绍的是Qt 字库移植并能显示中文,需要的字体库文件,一般是多个.具体移植那一个,看你使用的字库是什么了, ...
- VS 查看是否有内存泄露的方法
加入下列宏定义: #ifdef _DEBUG #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) #else #defi ...