KMP算法详解

初级KMP算法详解

所谓KMP算法,就是查找字符串中给定子串的位置,没有则返回特定数值。先介绍几个概念:

前缀

就是头部字串,比如China的前缀有C,Ch,Chi,Chin(不算最后一个字符)

后缀

就是尾部子串,China的后缀就是a,na,ina,hina(不算第一个字符)

部分匹配值

一个字符串的前缀集合和后缀集合的交集中,最长那个子串的长度
通常形如abxxab这样的部分匹配值就是2,因为前缀的ab和后缀的ab是共同和最长的(xx没有实际意义,但里面不应该有更长的)。

PM表

把子串的部分匹配值挨个写出来(懒得写了)随便写个例子:
str:abcac
a-0,b-0,c-0,a-1,c-0
移动位数 = 已匹配的字符数 - 对应的部分匹配值
这里用KMP算法为了减少匹配的次数,通过移动位数的方式

KMP算法中的next数组

这里首先声明一下KMP算法子串和主串的指针是如何移动的,以1为初始:

  1. 如果子串的指针指向0,也就是初始之前,子串和主串的指针就要同时往下一个移动,匹配子串的第一个字符和主串当前的字符;
  2. 如果子串指针指向的字符等于主串指针指向的字符,那么指针接着移动匹配下一个。
  3. 如果没匹配成功,则子串的指针按照对应的next数组进行跳转
    注意:无论是PM表还是next数组都是对应子串的,也就是看子串的部分匹配性
    next数组在这里就代表着子串接下来要跳转的指针和当前的i匹配,所以这里强调:
    next[j]就是在没匹配成功的时候,子串指针j跳转的目的地

next数组的实现

知道了next数组的意义,那么就剩实现next数组了,我这里提供一个理解的方法:
以1作为开始,也就是j=1是子串指针移到子串第一位时:

  1. 首先next[1]=0,代表我第一个失败我就接着匹配主串的下一个看看。比对第一个失败时j(子串指针)跳转到0,如果j跳转到0,主串和j都执行++,主串的指针就会移动!
  2. 然后next[n],n>1的话都代表第一个匹配成功了,如果没有特殊情况next[n]=1,代表的是这个对不上我用子串的第一个看看对的上不(重新匹配),要是对不上就再移动主串。
  3. 接下来就是特殊情况,是我自己总结的方便理解的版本,先说结论:
    假如n指针前面有那种部分匹配的串,形如abxxab那种,next[n]就等于部分匹配值+1

加个next数组简单的分析

再详细解释一下:n指针前面就是去掉n这个值看子串有没有长那样的。
就用ababa分析一下:

  1. 首先最开始的a是0,next[1] = 0
  2. ab去掉b看就剩a了,所以没什么特殊的。next[2] = 1
  3. aba去掉a看只剩ab了,也没啥特殊能匹配的,next[3] = 0
  4. abab去掉最后一个字符看只剩aba了,aba的部分匹配值就是1,next[4] = 2,假如4对不上我还能去2看看能不能对上,2再对不上我就只能接着去next[2]看看了
  5. ababa去掉最后一个字符看只剩abab,部分匹配值是2,next[5] = 3,5对不上我去3看看,放到字符串里也是很合理的,假如出现了ababc,这第二个ab也有可能对着子串的第一个ab,我也得去3看看不是。

nextval数组的构造

相比于字符next跳转增加逻辑判断,就比如ababa,假如第五个不是a,我要跳转next[5],但其实3我也一定匹配不成功,因为3检查的也还是a,那我肯定不是a啊,所以我一定会接着跳转next到[1]检查是不是a,也一定会跳转到0。所以不如直接把next[5]赋成0,这就是nextval数组,装的都是这种经过判断的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值