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数组的定义:

  1. void getNext(char subStr[],int next[])
  2. {
  3. int i = , j = i - ,k = -;
  4. next[] = -;
  5. while (i < strlen(subStr))
  6. {
  7. //k = -1时表示j指针回溯到第一个字符的位置
  8. //subStr[k] == subStr[i-1]表示第k个字符和i - 1个字符相等,属于情况二
  9. if (k == - || subStr[k] == subStr[i-])
  10. {
  11. next[i] = k + ;
  12. k = next[i];
  13. i++;
  14. }
  15. //情况三,不相等的话,要回溯j指针,subStr[j'] = subStr[i-1]的位置j'
  16. else
  17. {
  18. int t = i - ;
  19. while (t>=)
  20. {
  21. if (subStr[t] == subStr[i - ])
  22. {
  23. j = t;
  24. break;
  25. }
  26. t--;
  27. }
  28. if (t < )
  29. j = ;
  30. k = next[j];
  31. }
  32.  
  33. }
  34. }

  算法二,算法的设计思想和算法一大致相同

  1. void getNext(const char P[], int next[])
  2. {
  3. int q, k;
  4. int m = strlen(P);
  5. next[] = -;//模版字符串的第一个字符的最大前后缀长度为0
  6. for (q = ; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
  7. {
  8. k = next[q - ];
  9. while (k > && P[q - ] != P[k])//迭代地求出P[0]···P[q]的最大的相同的前后缀长度k
  10. {
  11. k--;
  12. }
  13.  
  14. if (P[q-] == P[k])//如果相等,那么最大相同前后缀长度加1
  15. {
  16. k++;
  17. }
  18. if (k == -)
  19. k = ;
  20. next[q] = k;
  21.  
  22. }
  23. }

  算法三,更加优化的求解next数组的算法

  1. void getNext(const char subStr[], int next[])
  2. {
  3. int i = , j = -;
  4. next[] = -;
  5. while (i < strlen(subStr))
  6. {
  7. //i从0开始的,属于情况二
  8. //j是前后缀长度
  9. if (j == - || subStr[i] == subStr[j])
  10. {
  11. i++;
  12. j++;
  13. next[i] = j;
  14. }
  15. //情况三,不同则j指针回溯
  16. else
  17. j = next[j];
  18. }
  19. }

  现在来进行总结一下,对于算法一和算法二来说,它们的时间复杂度是一样的,但是相对于算法三来说,虽然不如算法三高效,但是比较容易理解!

PS:如果有误的地方,请指出,共同进步!

那些有关求解next数组的算法的更多相关文章

  1. KMP算法番外篇--求解next数组

    KMP算法实现字符串的模式匹配的时间复杂度比朴素的模式匹配好很多,但是它时间效率的提高是有前提的,那就是:模式串的重复率很高,不然它的效率也不会凸显出来.在实际的应用中,KMP算法不算是使用率很高的一 ...

  2. KMP算法以及优化(代码分析以及求解next数组和nextval数组)

    KMP算法以及优化(代码分析以及求解next数组和nextval数组) 来了,数据结构及算法的内容来了,这才是我们的专攻,前面写的都是开胃小菜,本篇文章,侧重考研408方向,所以保证了你只要看懂了,题 ...

  3. 按照递推的思想求解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],很显 ...

  4. 在Eclipse中使用Junit进行单元测试练习 实现最大子数组和算法

    1.如何在MAC OS X下安装配置java开发工具 http://www.cnblogs.com/coderL/p/5939541.html 2.最大子数组和算法 附上程序运行及测试截图,源码见后 ...

  5. javascript数组去重算法-----3

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. javascript数组去重算法-----2

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. javascript数组去重算法-----1

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. javascript数组去重算法-----5

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. javascript数组去重算法-----4(另一种写法__2)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Android开发3——查看和输出日志信息

    一.错误级别 Error > Warn > Info > Debug > Verbose(冗余) 二.Android项目日志查看视图 Console视图只能看项目的部署到模拟器 ...

  2. python分析apahce网站日志的例子

    有关python实现apahce网站日志分析的方法. 应用到:shell与python数据交互.数据抓取,编码转换 #coding:utf-8 #!/usr/bin/python'''程序说明:apa ...

  3. linux批量备份服务器配置文件和目录的脚本

    这篇文章主要介绍了linux下批量备份服务器配置文件和目录的方法,需要的朋友可以参考下 功能:1. 只在备份机执行,远程的服务器只需要允许备份机用root通过密钥登录:2. 在备份机上配置需要备份哪些 ...

  4. XILINX XST综合的选项的含义

    所谓综合,就是将HDL语言.原理图等设计输入翻译成由与.或.非门和RAM.触发器等基本逻辑单元的逻辑连接(网表),并根据目标和要求(约束条件)优化所生成的逻辑连接,生成EDF文件.完成了输入.仿真以及 ...

  5. 【Android】19.1 SharedPreferences类

    分类:C#.Android.VS2015: 创建日期:2016-03-05 一.简介 SharedPreferences:简单共享存储首选项.实际上就是用加密的内部文件保存所有页面都能访问的一系列“n ...

  6. yii2 关系...

    link($name) 会使用..get$name...即有hasmany和hasone... // update lazily loaded related objects if (!$relati ...

  7. html5 canvas实现图片玻璃碎片特效

    今天要为大家带来一款html5 canvas实现的图片玻璃碎片特效.图片以玻璃碎片的形式出现到界面中,然后似玻璃被打碎的效果渐消息.效果图如下: 在线预览   源码下载 实现代码: html代码: & ...

  8. hive 定时加载分区

    #!/bin/bash #每天定时位外部表加载分区 #服务器当天的时间 #加载环境变量 source /etc/profile; #如果没有指定日期用当前日期如果指定的日期使用指定的日期 echo ' ...

  9. 【Visual Studio】解决方案未保存,请先保存你的解决方案,然后再管理Nuget包

    上网下的Demo,文件夹中没有.sln文件,用VS打开.csproj文件来打开方案.此时可能因为一些引用问题想打开Nuget包管理器,会弹出如下提示: 解决方案未保存,请先保存你的解决方案,然后再管理 ...

  10. WPF ListBoxItem DataTempldate command 执行问题

    今天用到MVVM,在listboxItem中做command处理.因为是要获取数据,修改ListBox模板,但是发现command无法正确执行,写在Item中可以正确执行. 网上也遇到类似问题,但是没 ...