再学习KMP算法——next数组、nextval数组

对于看毛片算法(KMP)其实我觉得对简单匹配效率提升不多= =  只有在模式串和主串之间存在很多“部分匹配”的时候,才显得比BF算法(最直观的匹配算法,一个一个匹配)效率高。但是KMP对指示主串的指针不必回溯,整个匹配过程对主串只用扫描一次,这对处理从外设输入的庞大文件很有效,可以边读入边匹配,无需重头读,效率很高。

 

PS:不懂KMP算法基本过程的可以先读一下我的另一篇博客 KMP算法

但是这个算法最难理解的地方就是:next数组怎么求??????????

这个问题真的困扰了我很久很久。看代码是不可能看代码的,这辈子是不会看代码的(手动狗头)。好了,废话不多说,怎么看懂代码其实不是很重要,毕竟同一个a+b程序,不同人写出的程序不一个样,打出代码的前提是理解算法过程。让我们直接开始吧:

在此先介绍一下前缀和后缀的概念,便于理解我从来不说严谨的定义,我是实用主义者。

前缀就是,对一个字符串“abcd”,去掉最后一个字符“d”得到的字符串“abc”。  就是去掉最后一个字符!!!

后缀就是,去掉第一个字符,对同一个字符串“abcd”,后缀就是“bcd”。

 

那么前缀后缀对next数组有什么用呢?

emmmm这个是很严谨的数学推导证明什么什么的,具体可以找别的文章来看,个人能力有限,这里就不写了(反正写了也没人看,都是代数,保证三分钟劝退)。

 

所以跳过推导这一步,我们直接开始看怎么用前缀后缀求next数组。

以下都对字符串“abaabcac”进行讨论。

首先我们约定next[1] = 0,next[2] = 1。

然后求后面的:

next[3] = 1。怎么来的?对第三位之前的串“ab”求前、后缀,前缀是“a”,后缀是“b”。然后求前、后缀重复的部分(注意:前缀必须从头开始截取,后缀从最后开始截取,不可以从中间开始截取相同的部分。  现在不理解注意里的这句话没关系,后面会详细介绍,先记住有这句话)。  很容易发现前、后缀重复的串为“”,长度为0,那么我们追偿个1,所以next[3] = 1;

next[4] = 2。同理此时前缀为“ab”,后缀为“ba”。重复的为串“a”,长度为1,追偿1,得到2.

next[5] = 2。此时前缀为“aba”,后缀为“baa”。重复串为“a”,长度为1,追偿1,得到2

next[6] = 3。此时前缀为“abaa”,后缀为“baab”。重复串为“ab”(注意不能是“baa”,因为这是从中间开始截取的,即上述注意的地方),长度为2,追偿1,得到3

next[7] = 1。此时前缀为“abaab”,后缀为“baabc”,重复部分为“”,长度为0,追偿1,得到1

next[8] = 2。此时前缀为“abaabc”,后缀为“baabca”,重复部分为“a”,长度为1,追偿1,得到2

 

好了,以上就是抛开代码算next数组的过程,

那么nextval数组怎么求呢?同样的道理,先抛开代码算法什么的,搞清楚这东西怎么来的。

首先nextval数组看名字都知道是从next数组演变过来的。假设我我们已经知道串和该串的next数组,即

T:        A   B  A  B  A  A  B  A  B

NEXT: 0   1  1  2  3  4   2   3   4

那么nextval的求法为:

约定nextval[1] = 0。

nextval[2] = 1。位置2上的字符为B,其next数组为1,则这个字符B与1位置上的字符A比较,不同则照抄next[2]数组,相同则继承1位置上的nextval数组的值。此处不同,故照抄next[2],为1.

nextval[3] = 0。位置3上的字符为A,找到next数组对应的1位置,与1位置上的字符A比较,相同,故继承nextval[1]的值,为0

nextval[4] = 1。位置4上的字符为B,找到next数组对应的2位置,与2位置上的字符B比较,相同,故继承nextval[2]的值,为1

nextval[5] = 0。位置5上的字符为A,找到next数组对应的3位置,与3位置上的字符A比较,相同,故继承nextval[3]的值,为0

nextval[6] = 4。位置6上的字符为A,找到next数组对应的4位置,与4位置上的字符B比较,不同,照抄nextval[6]上的值,为4

nextval[7] = 1。不推了= =复制粘贴没意思

nextval[8] = 0。

nextval[9] = 1。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值