KMP算法番外篇--求解next数组
KMP算法实现字符串的模式匹配的时间复杂度比朴素的模式匹配好很多,但是它时间效率的提高是有前提的,那就是:模式串的重复率很高,不然它的效率也不会凸显出来。在实际的应用中,KMP算法不算是使用率很高的一个算法,但是它的核心的那点东西却是使用率很高的,那就是next前缀数组的求解思路。在这次笔记中就单独摘出来,说一下前缀数组的求解。
1. next前缀数组的定义
不管做题还是推到算法,永远记住定义,这时最重要的东西。
2. next数组的暴力求解
这种方法的主要思路是:
为了求解nj的值,把的所有的前缀和后缀都找出来,然后从最大的开始匹配,直到找到合适的最长公共前缀后缀。如果没有,那么nj的值就是0。
前后缀的选取方式:
暴力算法就是在这里面不断的从最大的那个前缀和后缀逐一的匹配。
算法描述:
(1) 根据定义,初始化n[0] = –1。
(2) 从模式串的下标为1的位置,依次遍历整个模式串。对于每一个字符,当到达其下标j时,令k=j-1。
(3) 寻找它前面的字符串的最大公共前缀后缀,也就是判断的真假?
(4) 如果满足条件,令next[j]=k;如果不满足条件k--,继续执行(3)的步骤,直到k==0,然后令next[j]= 0。
代码实现:
#include <iostream>
#include <stdlib.h>
bool IsPatternMatch(char *p, int compareNum, int totalNum);
void ViolentGetNext(char *p, int *next); void main()
{
int next[];
char *str = "agctagcagctagctg";
ViolentGetNext(str, next); system("pause");
} void ViolentGetNext(char *p, int *next)
{
int pLen = strlen(p);
int k = ;
next[] = -; for(int j = ; j < pLen; j++)
{
k = j - ;
while(k > )
{
if(IsPatternMatch(p, k , j))
break;
else
k--;
}// while next[j] = k;
}// for
}
//param:copareNum代表了要比较的字节数
//param:totalNum代表了要比较的字节数
//上面的两个参数的作用就是定界前缀和后缀可能的范围
bool IsPatternMatch(char *p, int compareNum, int totalNum)
{
int i = ;
int j = totalNum - compareNum; for(; i < compareNum; i++, j++)
{
if(p[i] != p[j])
{
return false;
}
} return true;
}
具体的例子,假设字符串为ABCDABD
n[]的求解过程如下:
k=
ABCD≠BCDA,k=
ABC≠CDA,k=
AB≠DA,k=
A==A,n[]=k
3. next数组的递归求解
暴力求解每次在计算next[j]的时候都是独立的,而实际上求解next[j+1]是可以利用到next[0…j]的,这里的递归算法就是这样实现的。
设模式串为,现在已经计算出了next[0…j],如何计算next[j+1]?
利用前面求解的数值(这也是算法改进的地方,不让每个next元素都独立的计算),若已知next[j]=k,则对于模式串,肯定有这样的关系:
所以算法的描述可以是这样的:
(1) 如果k==-1(只有第一个字符的next值是-1),说明现在的位置是第二个位置,还不能算第二个它本身,所以next[j+1]=0,算法结束。
(2) 如果,理解这里的k是怎么从next[j]的值转换到了字符的下标值。则next[j+1]=k+1,算法结束。
提示:前面有分析过,求解next数组的过程的快捷方法就是不让他们独立的计算,还是继承前面计算好了的对称性。知道了next[j]的对称性,只需要在考察一下前缀和后缀的下一个字符是否相等就可以了。pk和pj就是之前最长前缀和后缀的下一个字符。
(3) 那么这个k’从哪里来的呢?看这个式子的两端就知道k’=next[k]。理解好上面的这个式子,就知道k‘是怎么来的了。
(4) 将k’赋值给k,转到步骤(1)。
代码实现:
//the recursion method to abtain the next array
//pLen is the length of the string
void RecursionGetNext(char *p, int pLen, int *next)
{ if(pLen == )
{
next[pLen - ] = -;
return;
} RecursionGetNext(p, pLen - , next); //pLen represents the number of the string
//pLen - 1 represents the index of the last character,that is the character that will be calculated in the next array.
//pLen - 1 - 1 represents the index of the sub-last character that has been calculated in the next array.
int k = next[pLen - ]; //k==-1 is a label showing that there is no prefix matching with postfix and the currently added character can not match neither.
//k==0 can only show that there is no prefix mathching with postfix,but pk may be match with pj
while(k >= )
{
if(p[pLen-] == p[k])
{
break;
}
else
{
k = next[k];
}
}//while next[pLen -] = k + ; }//RecursionGetNext()
4. next数组的递归展开求解
void GetNext(char *p, int *next)
{
int pLen = strlen(p);
int j = ;
int k = -;
next[] = -; while(j < pLen - )
{
//accroding to the depiction of the algorithm,the procedure can be programmed below:
//if(k == -1)
//{
// ++j;
// ++k;
// next[j] = k;
//}
//else if(p[j] == p[k])
//{
// ++j;
// ++k;
// next[j] = k;
//}
//but the fist two procedure can be reduced to one case: //p[j] == p[k] shows that we can inherite the feature of the string that matched alreay
//k==-1 shows two circumstance: 1.the beginning of the algorithm 2.there is no matched prefix and postfix and the last character is also defferent with the first one
if(k == - || p[j] == p[k])
{
++j;
++k;
next[j] = k;
}
else
{
k = next[k];
}
}//while
}
5. Reference Link
@wzhang1117的博客:https://www.zybuluo.com/wzhang1117/note/27431
KMP算法番外篇--求解next数组的更多相关文章
- 数据结构和算法 – 番外篇.时间测试类Timing
public class Timing { //startingTime--用来存储正在测试的代码的开始时间. TimeSpan startingTime; //duration--用来存储正在测试的 ...
- 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV
这次博客园的排版彻底残了..高清版请移步: https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程: 给深度学习入门者的Python快速教程 - 基础篇 给深度 ...
- 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)
目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...
- 可视化(番外篇)——SWT总结
本篇主要介绍如何在SWT下构建一个应用,如何安装SWT Designer并破解已进行SWT的可视化编程,Display以及Shell为何物.有何用,SWT中的常用组件.面板容器以及事件模型等. 1.可 ...
- python自动化测试应用-番外篇--接口测试1
篇1 book-python-auto-test-番外篇--接口测试1 --lamecho辣么丑 1.1概要 大家好! 我是lamecho(辣么丑),至今<安卓a ...
- [uboot] (番外篇)uboot之fdt介绍
http://blog.csdn.net/ooonebook/article/details/53206623 以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为 ...
- C++雾中风景番外篇:理解C++的复杂声明与声明解析
在学习C系列语言的过程之中,理解C/C++的复杂声明一直是初学者很困扰的问题.笔者初学之时也深受困扰,对很多规则死记硬背.后续在阅读<C专家编程>之后,尝试在编译器的角度来理解C/C++的 ...
- [uboot] (番外篇)uboot之fdt介绍 (转)
以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为例 [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(B ...
- (八)羽夏看C语言——C番外篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
随机推荐
- aliyun 启用ECS iptables
iptables -t nat -A POSTROUTING -s 0.0.0.0/24 -o eth0 -j MASQUERADEservice iptables saveecho 1 > / ...
- python IOError: invalid mode ('r') or filename
我想要用pandas.read_table()将数据表中的数据读到一个pandas DataFrame对象中: import pandas as pd unames = ['user_id', 'ge ...
- Android @+id与@id的区别
Android中的组件需要用一个int类型的值来表示,这个值也就是组件标签中的id属性值.id属性只能接受资源类型的值,也就是必须以@开头的值,例如,@id/abc.@+id/xyz等. 如果在@ ...
- cocos2d-x 3.0rc2 对于每个包执行情况的重要平台 (超级方便)
首先,你需要下载三个文件:每间 android-ndk android-sdk ant 下载位置可以随意:由于3.0rc2执行setup.py 自己主动搜索这三个文件 win32cmd以下: (1) ...
- S3C2416裸机开发系列十六_sd卡驱动实现
S3C2416裸机开发系列十六 sd卡驱动实现 象棋小子 1048272975 SD卡(Secure Digital Memory Card)具有体积小.容量大.传输数据快.可插拔.安全性好等长 ...
- XML编程与应用-读取XML
实例:使用XmlTextReader类的对象读取XML文档 代码如下 using System; using System.Collections.Generic; using System.Linq ...
- JAVA里的String、Timestamp、Date相互转换
Timestamp转化为String: SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//定义 ...
- 【Java并发编程】并发编程大合集-值得收藏
http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...
- JS脚本验证大全
/** * 2009-10-01 * 贺 臣 * 情 缘 * js各种表单数据验证 *//***************************************************** ...
- HOJ1014
Niven Numbers My Tags (Edit) Source : Unknown Time limit : 1 sec Memory limit : 32 M Submitt ...