那些有关求解next数组的算法
next数组的历史
有关字符串的模式匹配算法中,比较容易写出的是朴素的匹配算法也就是一种暴力求解方式,但是由于其时间复杂度为子串长度和主串长度的乘积,例如strlen(subStr) = n,strlen(mainStr) = m,则其时间复杂度为O(mn)。
为了能够得到更有效的匹配算法,D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特--莫里斯--普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。这也即是KMP算法的设计思想。
next数组的求解思路
求next数组,next[j]表示,当模式串j位置与主串i位置处发生不匹配时,i指针不回溯,j指针回溯到next[j]的位置。
对于求next[j]有三种情况:
1、j = 0时,next[j] = -1;//即模式串的第一个字符与主串i位置发生不匹配,应将i跳过当前位置,从下一个位置和模式串的第一个字符继续比较。
2、假设已知next[j] = k,即subStr[0,...,k-1] = subStr[j-k,j-1]。当subStr[k] = subStr[j]时,也就是说模式串满足subStr[0,...,k] = subStr[j-k,j],可以得知next[j+1] = k + 1 = next[j] + 1;
3、当subStr[k] != subStr[j]时,就需要从k位置之前去查找与subStr[j]匹配的位置,假设为j'。这样问题又可以转化为第二种情况,即next[j+1] = next[j'] + 1 = k' + 1。
三种求解next数组的算法
但是如何去求解next数组呢?有关这个问题,我思考了很长时间,下面给出几种算法:
算法一,严格根据next数组的定义:
void getNext(char subStr[],int next[])
{
int i = , j = i - ,k = -;
next[] = -;
while (i < strlen(subStr))
{
//k = -1时表示j指针回溯到第一个字符的位置
//subStr[k] == subStr[i-1]表示第k个字符和i - 1个字符相等,属于情况二
if (k == - || subStr[k] == subStr[i-])
{
next[i] = k + ;
k = next[i];
i++;
}
//情况三,不相等的话,要回溯j指针,subStr[j'] = subStr[i-1]的位置j'
else
{
int t = i - ;
while (t>=)
{
if (subStr[t] == subStr[i - ])
{
j = t;
break;
}
t--;
}
if (t < )
j = ;
k = next[j];
} }
}
算法二,算法的设计思想和算法一大致相同
void getNext(const char P[], int next[])
{
int q, k;
int m = strlen(P);
next[] = -;//模版字符串的第一个字符的最大前后缀长度为0
for (q = ; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
{
k = next[q - ];
while (k > && P[q - ] != P[k])//迭代地求出P[0]···P[q]的最大的相同的前后缀长度k
{
k--;
} if (P[q-] == P[k])//如果相等,那么最大相同前后缀长度加1
{
k++;
}
if (k == -)
k = ;
next[q] = k; }
}
算法三,更加优化的求解next数组的算法
void getNext(const char subStr[], int next[])
{
int i = , j = -;
next[] = -;
while (i < strlen(subStr))
{
//i从0开始的,属于情况二
//j是前后缀长度
if (j == - || subStr[i] == subStr[j])
{
i++;
j++;
next[i] = j;
}
//情况三,不同则j指针回溯
else
j = next[j];
}
}
现在来进行总结一下,对于算法一和算法二来说,它们的时间复杂度是一样的,但是相对于算法三来说,虽然不如算法三高效,但是比较容易理解!
PS:如果有误的地方,请指出,共同进步!
那些有关求解next数组的算法的更多相关文章
- KMP算法番外篇--求解next数组
KMP算法实现字符串的模式匹配的时间复杂度比朴素的模式匹配好很多,但是它时间效率的提高是有前提的,那就是:模式串的重复率很高,不然它的效率也不会凸显出来.在实际的应用中,KMP算法不算是使用率很高的一 ...
- KMP算法以及优化(代码分析以及求解next数组和nextval数组)
KMP算法以及优化(代码分析以及求解next数组和nextval数组) 来了,数据结构及算法的内容来了,这才是我们的专攻,前面写的都是开胃小菜,本篇文章,侧重考研408方向,所以保证了你只要看懂了,题 ...
- 按照递推的思想求解next[]数组
按照递推的思想求解next[]数组 根据定义next[0]=-1,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1] 若P[j]P[k],则有P[0..k]P[j-k,j],很显 ...
- 在Eclipse中使用Junit进行单元测试练习 实现最大子数组和算法
1.如何在MAC OS X下安装配置java开发工具 http://www.cnblogs.com/coderL/p/5939541.html 2.最大子数组和算法 附上程序运行及测试截图,源码见后 ...
- javascript数组去重算法-----3
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- javascript数组去重算法-----2
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- javascript数组去重算法-----1
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- javascript数组去重算法-----5
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- javascript数组去重算法-----4(另一种写法__2)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- 禁止用户使用密码的方式登录服务器,让其使用key的方式登录
这里我的远程登录工具xshell 所以这里我要做的是 第一步是在xshell中配置公私钥 密钥类型选择为rsa,长度为2048,并点击下一步,如下所示: 继续下一步 如果给密钥设置了密码,那么在使用这 ...
- PHP位操作符
二进制怎么算 http://www.doc88.com/p-474114598610.html 这个涉及到系统底层,WEB开发中几乎没用到,知道下有这个东西就好了.底层的东西解释总是简单不了的. 变量 ...
- 【Android】3.4 图层展示
分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 3.4 示例4--图层展示 一.简介 1.地图类型 百度地图Android SDK 3.7.1提供了两种类型的 ...
- 苹果开发小记(一):NSString 的比较用法
转自:http://blog.sina.com.cn/s/blog_897dd7be0100teh6.html 做了几个月的苹果,很多的思想方法都可以遵循一定规律来做的.NSString 比较字符串, ...
- angular学习笔记(九)-css类和样式3
再来看一个选择li列表的例子: 点击li中的任意项,被点击的li高亮显示: <!DOCTYPE html> <html ng-app> <head> <tit ...
- hdoj1251 统计难题 字典树
统计难题 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)Total Submi ...
- 前端面试题 -- JS篇
前端面试题 -- JS篇 类型 1.js中有哪些数据类型,并解释清楚原始数据类型和引用数据类型 js中共有null,undefined, string,number,boolean,object六种数 ...
- MySQL通过视图(或临时表)实现动态SQL(游标)
>参考de优秀文章 写MySQL存储过程实现动态执行SQL Dynamic cursor in stored procedure MySQL通过视图(或临时表)实现动态SQL(游标). 因在实现 ...
- arm程序的反汇编程序
这是汇编源文件: MCU:S3C2440(arm920T) 代码实现点亮个led小灯 .text .global _start _start: ldr r0,=0x56000010 @GPBCON m ...
- 【转】hadoop2.6 配置lzo压缩
[转自]http://my.oschina.net/u/1169079/blog/225070 经常用于处理大量的数据,如果期间的输出数据.中间数据能压缩存储,对系统的I/O性能会有提升.综合考虑压缩 ...